From c27dd5bedb7a499009c51ebd6f1f62756770ff26 Mon Sep 17 00:00:00 2001 From: Felix Soubelet Date: Thu, 8 Jan 2026 10:57:02 +0100 Subject: [PATCH 01/70] min version of 3.11 like scientific ecosystem, update classifiers --- pyproject.toml | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/pyproject.toml b/pyproject.toml index d9354b85..b05ea381 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -26,7 +26,7 @@ authors = [ ] license = "MIT" dynamic = ["version"] -requires-python = ">=3.10" +requires-python = ">=3.11" keywords = [ "PHD", @@ -42,11 +42,10 @@ classifiers = [ "Natural Language :: English", "Programming Language :: Python", "Programming Language :: Python :: 3 :: Only", - "Programming Language :: Python :: 3.8", - "Programming Language :: Python :: 3.9", - "Programming Language :: Python :: 3.10", "Programming Language :: Python :: 3.11", "Programming Language :: Python :: 3.12", + "Programming Language :: Python :: 3.13", + "Programming Language :: Python :: 3.14", "Programming Language :: Python :: Implementation :: CPython", "Topic :: Scientific/Engineering", "Topic :: Scientific/Engineering :: Physics", From bcb1e6d6a56a4bded6a4f825263d5c13a3b3495b Mon Sep 17 00:00:00 2001 From: Felix Soubelet Date: Thu, 8 Jan 2026 11:01:02 +0100 Subject: [PATCH 02/70] move rich and pendulum to monitor extra deps, propagate to tests and all as well --- pyproject.toml | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-) diff --git a/pyproject.toml b/pyproject.toml index b05ea381..6c5f130d 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -54,20 +54,25 @@ classifiers = [ ] dependencies = [ + # -- Core scientific -- # "numpy >= 2.0", "pandas >= 2.0", "matplotlib >=3.7", "scipy >= 1.10", + # -- Domain specific -- # + "cpymad >= 1.16", "tfs-pandas >= 3.8", + "optics-functions >= 0.1", + # -- Utilities -- # "loguru < 1.0", - "cpymad >= 1.16", - "rich >= 13.0", "pydantic >= 2.0", - "pendulum >= 3.0", - "optics-functions >= 0.1", ] [project.optional-dependencies] +monitor = [ + "rich >= 13.0", + "pendulum >= 3.0", +] test = [ "pytest >= 8.0", "pytest-cov >= 6.0", @@ -77,6 +82,7 @@ test = [ "pytest-randomly >= 3.10", "coverage[toml] >= 7.0", "pytest-mpl >= 0.14", + "pyhdtoolkit[monitor]", ] dev = [ "ruff >= 0.12", @@ -98,6 +104,7 @@ all = [ "pyhdtoolkit[dev]", "pyhdtoolkit[docs]", "pyhdtoolkit[test]", + "pyhdtoolkit[monitor]", ] [project.urls] From 698883c4b795f13e9452a870d54647d0b6260acc Mon Sep 17 00:00:00 2001 From: Felix Soubelet Date: Thu, 8 Jan 2026 11:01:15 +0100 Subject: [PATCH 03/70] update lockfile --- uv.lock | 466 +++++++------------------------------------------------- 1 file changed, 56 insertions(+), 410 deletions(-) diff --git a/uv.lock b/uv.lock index 9d578d76..9e1f5af2 100644 --- a/uv.lock +++ b/uv.lock @@ -1,10 +1,9 @@ version = 1 revision = 3 -requires-python = ">=3.10" +requires-python = ">=3.11" resolution-markers = [ "python_full_version >= '3.12'", - "python_full_version == '3.11.*'", - "python_full_version < '3.11'", + "python_full_version < '3.12'", ] [[package]] @@ -65,18 +64,6 @@ dependencies = [ ] sdist = { url = "https://files.pythonhosted.org/packages/fc/97/c783634659c2920c3fc70419e3af40972dbaf758daa229a7d6ea6135c90d/cffi-1.17.1.tar.gz", hash = "sha256:1c39c6016c32bc48dd54561950ebd6836e1670f2ae46128f67cf49e789c52824", size = 516621, upload-time = "2024-09-04T20:45:21.852Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/90/07/f44ca684db4e4f08a3fdc6eeb9a0d15dc6883efc7b8c90357fdbf74e186c/cffi-1.17.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:df8b1c11f177bc2313ec4b2d46baec87a5f3e71fc8b45dab2ee7cae86d9aba14", size = 182191, upload-time = "2024-09-04T20:43:30.027Z" }, - { url = "https://files.pythonhosted.org/packages/08/fd/cc2fedbd887223f9f5d170c96e57cbf655df9831a6546c1727ae13fa977a/cffi-1.17.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:8f2cdc858323644ab277e9bb925ad72ae0e67f69e804f4898c070998d50b1a67", size = 178592, upload-time = "2024-09-04T20:43:32.108Z" }, - { url = "https://files.pythonhosted.org/packages/de/cc/4635c320081c78d6ffc2cab0a76025b691a91204f4aa317d568ff9280a2d/cffi-1.17.1-cp310-cp310-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:edae79245293e15384b51f88b00613ba9f7198016a5948b5dddf4917d4d26382", size = 426024, upload-time = "2024-09-04T20:43:34.186Z" }, - { url = "https://files.pythonhosted.org/packages/b6/7b/3b2b250f3aab91abe5f8a51ada1b717935fdaec53f790ad4100fe2ec64d1/cffi-1.17.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:45398b671ac6d70e67da8e4224a065cec6a93541bb7aebe1b198a61b58c7b702", size = 448188, upload-time = "2024-09-04T20:43:36.286Z" }, - { url = "https://files.pythonhosted.org/packages/d3/48/1b9283ebbf0ec065148d8de05d647a986c5f22586b18120020452fff8f5d/cffi-1.17.1-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:ad9413ccdeda48c5afdae7e4fa2192157e991ff761e7ab8fdd8926f40b160cc3", size = 455571, upload-time = "2024-09-04T20:43:38.586Z" }, - { url = "https://files.pythonhosted.org/packages/40/87/3b8452525437b40f39ca7ff70276679772ee7e8b394934ff60e63b7b090c/cffi-1.17.1-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:5da5719280082ac6bd9aa7becb3938dc9f9cbd57fac7d2871717b1feb0902ab6", size = 436687, upload-time = "2024-09-04T20:43:40.084Z" }, - { url = "https://files.pythonhosted.org/packages/8d/fb/4da72871d177d63649ac449aec2e8a29efe0274035880c7af59101ca2232/cffi-1.17.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:2bb1a08b8008b281856e5971307cc386a8e9c5b625ac297e853d36da6efe9c17", size = 446211, upload-time = "2024-09-04T20:43:41.526Z" }, - { url = "https://files.pythonhosted.org/packages/ab/a0/62f00bcb411332106c02b663b26f3545a9ef136f80d5df746c05878f8c4b/cffi-1.17.1-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:045d61c734659cc045141be4bae381a41d89b741f795af1dd018bfb532fd0df8", size = 461325, upload-time = "2024-09-04T20:43:43.117Z" }, - { url = "https://files.pythonhosted.org/packages/36/83/76127035ed2e7e27b0787604d99da630ac3123bfb02d8e80c633f218a11d/cffi-1.17.1-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:6883e737d7d9e4899a8a695e00ec36bd4e5e4f18fabe0aca0efe0a4b44cdb13e", size = 438784, upload-time = "2024-09-04T20:43:45.256Z" }, - { url = "https://files.pythonhosted.org/packages/21/81/a6cd025db2f08ac88b901b745c163d884641909641f9b826e8cb87645942/cffi-1.17.1-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:6b8b4a92e1c65048ff98cfe1f735ef8f1ceb72e3d5f0c25fdb12087a23da22be", size = 461564, upload-time = "2024-09-04T20:43:46.779Z" }, - { url = "https://files.pythonhosted.org/packages/f8/fe/4d41c2f200c4a457933dbd98d3cf4e911870877bd94d9656cc0fcb390681/cffi-1.17.1-cp310-cp310-win32.whl", hash = "sha256:c9c3d058ebabb74db66e431095118094d06abf53284d9c81f27300d0e0d8bc7c", size = 171804, upload-time = "2024-09-04T20:43:48.186Z" }, - { url = "https://files.pythonhosted.org/packages/d1/b6/0b0f5ab93b0df4acc49cae758c81fe4e5ef26c3ae2e10cc69249dfd8b3ab/cffi-1.17.1-cp310-cp310-win_amd64.whl", hash = "sha256:0f048dcf80db46f0098ccac01132761580d28e28bc0f78ae0d58048063317e15", size = 181299, upload-time = "2024-09-04T20:43:49.812Z" }, { url = "https://files.pythonhosted.org/packages/6b/f4/927e3a8899e52a27fa57a48607ff7dc91a9ebe97399b357b85a0c7892e00/cffi-1.17.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:a45e3c6913c5b87b3ff120dcdc03f6131fa0065027d0ed7ee6190736a74cd401", size = 182264, upload-time = "2024-09-04T20:43:51.124Z" }, { url = "https://files.pythonhosted.org/packages/6c/f5/6c3a8efe5f503175aaddcbea6ad0d2c96dad6f5abb205750d1b3df44ef29/cffi-1.17.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:30c5e0cb5ae493c04c8b42916e52ca38079f1b235c2f8ae5f4527b963c401caf", size = 178651, upload-time = "2024-09-04T20:43:52.872Z" }, { url = "https://files.pythonhosted.org/packages/94/dd/a3f0118e688d1b1a57553da23b16bdade96d2f9bcda4d32e7d2838047ff7/cffi-1.17.1-cp311-cp311-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:f75c7ab1f9e4aca5414ed4d8e5c0e303a34f4421f8a0d47a4d019ceff0ab6af4", size = 445259, upload-time = "2024-09-04T20:43:56.123Z" }, @@ -119,19 +106,6 @@ version = "3.4.2" source = { registry = "https://pypi.org/simple" } sdist = { url = "https://files.pythonhosted.org/packages/e4/33/89c2ced2b67d1c2a61c19c6751aa8902d46ce3dacb23600a283619f5a12d/charset_normalizer-3.4.2.tar.gz", hash = "sha256:5baececa9ecba31eff645232d59845c07aa030f0c81ee70184a90d35099a0e63", size = 126367, upload-time = "2025-05-02T08:34:42.01Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/95/28/9901804da60055b406e1a1c5ba7aac1276fb77f1dde635aabfc7fd84b8ab/charset_normalizer-3.4.2-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:7c48ed483eb946e6c04ccbe02c6b4d1d48e51944b6db70f697e089c193404941", size = 201818, upload-time = "2025-05-02T08:31:46.725Z" }, - { url = "https://files.pythonhosted.org/packages/d9/9b/892a8c8af9110935e5adcbb06d9c6fe741b6bb02608c6513983048ba1a18/charset_normalizer-3.4.2-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b2d318c11350e10662026ad0eb71bb51c7812fc8590825304ae0bdd4ac283acd", size = 144649, upload-time = "2025-05-02T08:31:48.889Z" }, - { url = "https://files.pythonhosted.org/packages/7b/a5/4179abd063ff6414223575e008593861d62abfc22455b5d1a44995b7c101/charset_normalizer-3.4.2-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:9cbfacf36cb0ec2897ce0ebc5d08ca44213af24265bd56eca54bee7923c48fd6", size = 155045, upload-time = "2025-05-02T08:31:50.757Z" }, - { url = "https://files.pythonhosted.org/packages/3b/95/bc08c7dfeddd26b4be8c8287b9bb055716f31077c8b0ea1cd09553794665/charset_normalizer-3.4.2-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:18dd2e350387c87dabe711b86f83c9c78af772c748904d372ade190b5c7c9d4d", size = 147356, upload-time = "2025-05-02T08:31:52.634Z" }, - { url = "https://files.pythonhosted.org/packages/a8/2d/7a5b635aa65284bf3eab7653e8b4151ab420ecbae918d3e359d1947b4d61/charset_normalizer-3.4.2-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8075c35cd58273fee266c58c0c9b670947c19df5fb98e7b66710e04ad4e9ff86", size = 149471, upload-time = "2025-05-02T08:31:56.207Z" }, - { url = "https://files.pythonhosted.org/packages/ae/38/51fc6ac74251fd331a8cfdb7ec57beba8c23fd5493f1050f71c87ef77ed0/charset_normalizer-3.4.2-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:5bf4545e3b962767e5c06fe1738f951f77d27967cb2caa64c28be7c4563e162c", size = 151317, upload-time = "2025-05-02T08:31:57.613Z" }, - { url = "https://files.pythonhosted.org/packages/b7/17/edee1e32215ee6e9e46c3e482645b46575a44a2d72c7dfd49e49f60ce6bf/charset_normalizer-3.4.2-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:7a6ab32f7210554a96cd9e33abe3ddd86732beeafc7a28e9955cdf22ffadbab0", size = 146368, upload-time = "2025-05-02T08:31:59.468Z" }, - { url = "https://files.pythonhosted.org/packages/26/2c/ea3e66f2b5f21fd00b2825c94cafb8c326ea6240cd80a91eb09e4a285830/charset_normalizer-3.4.2-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:b33de11b92e9f75a2b545d6e9b6f37e398d86c3e9e9653c4864eb7e89c5773ef", size = 154491, upload-time = "2025-05-02T08:32:01.219Z" }, - { url = "https://files.pythonhosted.org/packages/52/47/7be7fa972422ad062e909fd62460d45c3ef4c141805b7078dbab15904ff7/charset_normalizer-3.4.2-cp310-cp310-musllinux_1_2_ppc64le.whl", hash = "sha256:8755483f3c00d6c9a77f490c17e6ab0c8729e39e6390328e42521ef175380ae6", size = 157695, upload-time = "2025-05-02T08:32:03.045Z" }, - { url = "https://files.pythonhosted.org/packages/2f/42/9f02c194da282b2b340f28e5fb60762de1151387a36842a92b533685c61e/charset_normalizer-3.4.2-cp310-cp310-musllinux_1_2_s390x.whl", hash = "sha256:68a328e5f55ec37c57f19ebb1fdc56a248db2e3e9ad769919a58672958e8f366", size = 154849, upload-time = "2025-05-02T08:32:04.651Z" }, - { url = "https://files.pythonhosted.org/packages/67/44/89cacd6628f31fb0b63201a618049be4be2a7435a31b55b5eb1c3674547a/charset_normalizer-3.4.2-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:21b2899062867b0e1fde9b724f8aecb1af14f2778d69aacd1a5a1853a597a5db", size = 150091, upload-time = "2025-05-02T08:32:06.719Z" }, - { url = "https://files.pythonhosted.org/packages/1f/79/4b8da9f712bc079c0f16b6d67b099b0b8d808c2292c937f267d816ec5ecc/charset_normalizer-3.4.2-cp310-cp310-win32.whl", hash = "sha256:e8082b26888e2f8b36a042a58307d5b917ef2b1cacab921ad3323ef91901c71a", size = 98445, upload-time = "2025-05-02T08:32:08.66Z" }, - { url = "https://files.pythonhosted.org/packages/7d/d7/96970afb4fb66497a40761cdf7bd4f6fca0fc7bafde3a84f836c1f57a926/charset_normalizer-3.4.2-cp310-cp310-win_amd64.whl", hash = "sha256:f69a27e45c43520f5487f27627059b64aaf160415589230992cec34c5e18a509", size = 105782, upload-time = "2025-05-02T08:32:10.46Z" }, { url = "https://files.pythonhosted.org/packages/05/85/4c40d00dcc6284a1c1ad5de5e0996b06f39d8232f1031cd23c2f5c07ee86/charset_normalizer-3.4.2-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:be1e352acbe3c78727a16a455126d9ff83ea2dfdcbc83148d2982305a04714c2", size = 198794, upload-time = "2025-05-02T08:32:11.945Z" }, { url = "https://files.pythonhosted.org/packages/41/d9/7a6c0b9db952598e97e93cbdfcb91bacd89b9b88c7c983250a77c008703c/charset_normalizer-3.4.2-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:aa88ca0b1932e93f2d961bf3addbb2db902198dca337d88c89e1559e066e7645", size = 142846, upload-time = "2025-05-02T08:32:13.946Z" }, { url = "https://files.pythonhosted.org/packages/66/82/a37989cda2ace7e37f36c1a8ed16c58cf48965a79c2142713244bf945c89/charset_normalizer-3.4.2-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:d524ba3f1581b35c03cb42beebab4a13e6cdad7b36246bd22541fa585a56cccd", size = 153350, upload-time = "2025-05-02T08:32:15.873Z" }, @@ -192,16 +166,6 @@ dependencies = [ ] sdist = { url = "https://files.pythonhosted.org/packages/66/54/eb9bfc647b19f2009dd5c7f5ec51c4e6ca831725f1aea7a993034f483147/contourpy-1.3.2.tar.gz", hash = "sha256:b6945942715a034c671b7fc54f9588126b0b8bf23db2696e3ca8328f3ff0ab54", size = 13466130, upload-time = "2025-04-15T17:47:53.79Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/12/a3/da4153ec8fe25d263aa48c1a4cbde7f49b59af86f0b6f7862788c60da737/contourpy-1.3.2-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:ba38e3f9f330af820c4b27ceb4b9c7feee5fe0493ea53a8720f4792667465934", size = 268551, upload-time = "2025-04-15T17:34:46.581Z" }, - { url = "https://files.pythonhosted.org/packages/2f/6c/330de89ae1087eb622bfca0177d32a7ece50c3ef07b28002de4757d9d875/contourpy-1.3.2-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:dc41ba0714aa2968d1f8674ec97504a8f7e334f48eeacebcaa6256213acb0989", size = 253399, upload-time = "2025-04-15T17:34:51.427Z" }, - { url = "https://files.pythonhosted.org/packages/c1/bd/20c6726b1b7f81a8bee5271bed5c165f0a8e1f572578a9d27e2ccb763cb2/contourpy-1.3.2-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:9be002b31c558d1ddf1b9b415b162c603405414bacd6932d031c5b5a8b757f0d", size = 312061, upload-time = "2025-04-15T17:34:55.961Z" }, - { url = "https://files.pythonhosted.org/packages/22/fc/a9665c88f8a2473f823cf1ec601de9e5375050f1958cbb356cdf06ef1ab6/contourpy-1.3.2-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:8d2e74acbcba3bfdb6d9d8384cdc4f9260cae86ed9beee8bd5f54fee49a430b9", size = 351956, upload-time = "2025-04-15T17:35:00.992Z" }, - { url = "https://files.pythonhosted.org/packages/25/eb/9f0a0238f305ad8fb7ef42481020d6e20cf15e46be99a1fcf939546a177e/contourpy-1.3.2-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:e259bced5549ac64410162adc973c5e2fb77f04df4a439d00b478e57a0e65512", size = 320872, upload-time = "2025-04-15T17:35:06.177Z" }, - { url = "https://files.pythonhosted.org/packages/32/5c/1ee32d1c7956923202f00cf8d2a14a62ed7517bdc0ee1e55301227fc273c/contourpy-1.3.2-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ad687a04bc802cbe8b9c399c07162a3c35e227e2daccf1668eb1f278cb698631", size = 325027, upload-time = "2025-04-15T17:35:11.244Z" }, - { url = "https://files.pythonhosted.org/packages/83/bf/9baed89785ba743ef329c2b07fd0611d12bfecbedbdd3eeecf929d8d3b52/contourpy-1.3.2-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:cdd22595308f53ef2f891040ab2b93d79192513ffccbd7fe19be7aa773a5e09f", size = 1306641, upload-time = "2025-04-15T17:35:26.701Z" }, - { url = "https://files.pythonhosted.org/packages/d4/cc/74e5e83d1e35de2d28bd97033426b450bc4fd96e092a1f7a63dc7369b55d/contourpy-1.3.2-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:b4f54d6a2defe9f257327b0f243612dd051cc43825587520b1bf74a31e2f6ef2", size = 1374075, upload-time = "2025-04-15T17:35:43.204Z" }, - { url = "https://files.pythonhosted.org/packages/0c/42/17f3b798fd5e033b46a16f8d9fcb39f1aba051307f5ebf441bad1ecf78f8/contourpy-1.3.2-cp310-cp310-win32.whl", hash = "sha256:f939a054192ddc596e031e50bb13b657ce318cf13d264f095ce9db7dc6ae81c0", size = 177534, upload-time = "2025-04-15T17:35:46.554Z" }, - { url = "https://files.pythonhosted.org/packages/54/ec/5162b8582f2c994721018d0c9ece9dc6ff769d298a8ac6b6a652c307e7df/contourpy-1.3.2-cp310-cp310-win_amd64.whl", hash = "sha256:c440093bbc8fc21c637c03bafcbef95ccd963bc6e0514ad887932c18ca2a759a", size = 221188, upload-time = "2025-04-15T17:35:50.064Z" }, { url = "https://files.pythonhosted.org/packages/b3/b9/ede788a0b56fc5b071639d06c33cb893f68b1178938f3425debebe2dab78/contourpy-1.3.2-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:6a37a2fb93d4df3fc4c0e363ea4d16f83195fc09c891bc8ce072b9d084853445", size = 269636, upload-time = "2025-04-15T17:35:54.473Z" }, { url = "https://files.pythonhosted.org/packages/e6/75/3469f011d64b8bbfa04f709bfc23e1dd71be54d05b1b083be9f5b22750d1/contourpy-1.3.2-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:b7cd50c38f500bbcc9b6a46643a40e0913673f869315d8e70de0438817cb7773", size = 254636, upload-time = "2025-04-15T17:35:58.283Z" }, { url = "https://files.pythonhosted.org/packages/8d/2f/95adb8dae08ce0ebca4fd8e7ad653159565d9739128b2d5977806656fcd2/contourpy-1.3.2-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d6658ccc7251a4433eebd89ed2672c2ed96fba367fd25ca9512aa92a4b46c4f1", size = 313053, upload-time = "2025-04-15T17:36:03.235Z" }, @@ -242,9 +206,6 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/78/73/69dd9a024444489e22d86108e7b913f3528f56cfc312b5c5727a44188471/contourpy-1.3.2-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:e298e7e70cf4eb179cc1077be1c725b5fd131ebc81181bf0c03525c8abc297fd", size = 1372168, upload-time = "2025-04-15T17:44:33.43Z" }, { url = "https://files.pythonhosted.org/packages/0f/1b/96d586ccf1b1a9d2004dd519b25fbf104a11589abfd05484ff12199cca21/contourpy-1.3.2-cp313-cp313t-win32.whl", hash = "sha256:d0e589ae0d55204991450bb5c23f571c64fe43adaa53f93fc902a84c96f52fe1", size = 189550, upload-time = "2025-04-15T17:44:37.092Z" }, { url = "https://files.pythonhosted.org/packages/b0/e6/6000d0094e8a5e32ad62591c8609e269febb6e4db83a1c75ff8868b42731/contourpy-1.3.2-cp313-cp313t-win_amd64.whl", hash = "sha256:78e9253c3de756b3f6a5174d024c4835acd59eb3f8e2ca13e775dbffe1558f69", size = 238214, upload-time = "2025-04-15T17:44:40.827Z" }, - { url = "https://files.pythonhosted.org/packages/33/05/b26e3c6ecc05f349ee0013f0bb850a761016d89cec528a98193a48c34033/contourpy-1.3.2-pp310-pypy310_pp73-macosx_10_15_x86_64.whl", hash = "sha256:fd93cc7f3139b6dd7aab2f26a90dde0aa9fc264dbf70f6740d498a70b860b82c", size = 265681, upload-time = "2025-04-15T17:44:59.314Z" }, - { url = "https://files.pythonhosted.org/packages/2b/25/ac07d6ad12affa7d1ffed11b77417d0a6308170f44ff20fa1d5aa6333f03/contourpy-1.3.2-pp310-pypy310_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:107ba8a6a7eec58bb475329e6d3b95deba9440667c4d62b9b6063942b61d7f16", size = 315101, upload-time = "2025-04-15T17:45:04.165Z" }, - { url = "https://files.pythonhosted.org/packages/8f/4d/5bb3192bbe9d3f27e3061a6a8e7733c9120e203cb8515767d30973f71030/contourpy-1.3.2-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:ded1706ed0c1049224531b81128efbd5084598f18d8a2d9efae833edbd2b40ad", size = 220599, upload-time = "2025-04-15T17:45:08.456Z" }, { url = "https://files.pythonhosted.org/packages/ff/c0/91f1215d0d9f9f343e4773ba6c9b89e8c0cc7a64a6263f21139da639d848/contourpy-1.3.2-pp311-pypy311_pp73-macosx_10_15_x86_64.whl", hash = "sha256:5f5964cdad279256c084b69c3f412b7801e15356b16efa9d78aa974041903da0", size = 266807, upload-time = "2025-04-15T17:45:15.535Z" }, { url = "https://files.pythonhosted.org/packages/d4/79/6be7e90c955c0487e7712660d6cead01fa17bff98e0ea275737cc2bc8e71/contourpy-1.3.2-pp311-pypy311_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:49b65a95d642d4efa8f64ba12558fcb83407e58a2dfba9d796d77b63ccfcaff5", size = 318729, upload-time = "2025-04-15T17:45:20.166Z" }, { url = "https://files.pythonhosted.org/packages/87/68/7f46fb537958e87427d98a4074bcde4b67a70b04900cfc5ce29bc2f556c1/contourpy-1.3.2-pp311-pypy311_pp73-win_amd64.whl", hash = "sha256:8c5acb8dddb0752bf252e01a3035b21443158910ac16a3b0d20e7fed7d534ce5", size = 221791, upload-time = "2025-04-15T17:45:24.794Z" }, @@ -256,16 +217,6 @@ version = "7.9.1" source = { registry = "https://pypi.org/simple" } sdist = { url = "https://files.pythonhosted.org/packages/e7/e0/98670a80884f64578f0c22cd70c5e81a6e07b08167721c7487b4d70a7ca0/coverage-7.9.1.tar.gz", hash = "sha256:6cf43c78c4282708a28e466316935ec7489a9c487518a77fa68f716c67909cec", size = 813650, upload-time = "2025-06-13T13:02:28.627Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/c1/78/1c1c5ec58f16817c09cbacb39783c3655d54a221b6552f47ff5ac9297603/coverage-7.9.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:cc94d7c5e8423920787c33d811c0be67b7be83c705f001f7180c7b186dcf10ca", size = 212028, upload-time = "2025-06-13T13:00:29.293Z" }, - { url = "https://files.pythonhosted.org/packages/98/db/e91b9076f3a888e3b4ad7972ea3842297a52cc52e73fd1e529856e473510/coverage-7.9.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:16aa0830d0c08a2c40c264cef801db8bc4fc0e1892782e45bcacbd5889270509", size = 212420, upload-time = "2025-06-13T13:00:34.027Z" }, - { url = "https://files.pythonhosted.org/packages/0e/d0/2b3733412954576b0aea0a16c3b6b8fbe95eb975d8bfa10b07359ead4252/coverage-7.9.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:cf95981b126f23db63e9dbe4cf65bd71f9a6305696fa5e2262693bc4e2183f5b", size = 241529, upload-time = "2025-06-13T13:00:35.786Z" }, - { url = "https://files.pythonhosted.org/packages/b3/00/5e2e5ae2e750a872226a68e984d4d3f3563cb01d1afb449a17aa819bc2c4/coverage-7.9.1-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:f05031cf21699785cd47cb7485f67df619e7bcdae38e0fde40d23d3d0210d3c3", size = 239403, upload-time = "2025-06-13T13:00:37.399Z" }, - { url = "https://files.pythonhosted.org/packages/37/3b/a2c27736035156b0a7c20683afe7df498480c0dfdf503b8c878a21b6d7fb/coverage-7.9.1-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:bb4fbcab8764dc072cb651a4bcda4d11fb5658a1d8d68842a862a6610bd8cfa3", size = 240548, upload-time = "2025-06-13T13:00:39.647Z" }, - { url = "https://files.pythonhosted.org/packages/98/f5/13d5fc074c3c0e0dc80422d9535814abf190f1254d7c3451590dc4f8b18c/coverage-7.9.1-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:0f16649a7330ec307942ed27d06ee7e7a38417144620bb3d6e9a18ded8a2d3e5", size = 240459, upload-time = "2025-06-13T13:00:40.934Z" }, - { url = "https://files.pythonhosted.org/packages/36/24/24b9676ea06102df824c4a56ffd13dc9da7904478db519efa877d16527d5/coverage-7.9.1-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:cea0a27a89e6432705fffc178064503508e3c0184b4f061700e771a09de58187", size = 239128, upload-time = "2025-06-13T13:00:42.343Z" }, - { url = "https://files.pythonhosted.org/packages/be/05/242b7a7d491b369ac5fee7908a6e5ba42b3030450f3ad62c645b40c23e0e/coverage-7.9.1-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:e980b53a959fa53b6f05343afbd1e6f44a23ed6c23c4b4c56c6662bbb40c82ce", size = 239402, upload-time = "2025-06-13T13:00:43.634Z" }, - { url = "https://files.pythonhosted.org/packages/73/e0/4de7f87192fa65c9c8fbaeb75507e124f82396b71de1797da5602898be32/coverage-7.9.1-cp310-cp310-win32.whl", hash = "sha256:70760b4c5560be6ca70d11f8988ee6542b003f982b32f83d5ac0b72476607b70", size = 214518, upload-time = "2025-06-13T13:00:45.622Z" }, - { url = "https://files.pythonhosted.org/packages/d5/ab/5e4e2fe458907d2a65fab62c773671cfc5ac704f1e7a9ddd91996f66e3c2/coverage-7.9.1-cp310-cp310-win_amd64.whl", hash = "sha256:a66e8f628b71f78c0e0342003d53b53101ba4e00ea8dabb799d9dba0abbbcebe", size = 215436, upload-time = "2025-06-13T13:00:47.245Z" }, { url = "https://files.pythonhosted.org/packages/60/34/fa69372a07d0903a78ac103422ad34db72281c9fc625eba94ac1185da66f/coverage-7.9.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:95c765060e65c692da2d2f51a9499c5e9f5cf5453aeaf1420e3fc847cc060582", size = 212146, upload-time = "2025-06-13T13:00:48.496Z" }, { url = "https://files.pythonhosted.org/packages/27/f0/da1894915d2767f093f081c42afeba18e760f12fdd7a2f4acbe00564d767/coverage-7.9.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:ba383dc6afd5ec5b7a0d0c23d38895db0e15bcba7fb0fa8901f245267ac30d86", size = 212536, upload-time = "2025-06-13T13:00:51.535Z" }, { url = "https://files.pythonhosted.org/packages/10/d5/3fc33b06e41e390f88eef111226a24e4504d216ab8e5d1a7089aa5a3c87a/coverage-7.9.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:37ae0383f13cbdcf1e5e7014489b0d71cc0106458878ccde52e8a12ced4298ed", size = 245092, upload-time = "2025-06-13T13:00:52.883Z" }, @@ -329,11 +280,6 @@ dependencies = [ ] sdist = { url = "https://files.pythonhosted.org/packages/50/d5/84b9ed10b6c3bb472931a2bc77cf7bd498e3e535d784ee5cc56c3841b98b/cpymad-1.17.0.tar.gz", hash = "sha256:0a9d1e6c85b1574b698d7c231cb1d6f72e452a80562bc2a7304975bb20d3bbe3", size = 54759, upload-time = "2024-12-28T11:21:31.302Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/35/41/046796c2861d34a781eb53b48d629497d67d147618e27d000bf29ea6984b/cpymad-1.17.0-cp310-cp310-macosx_13_0_arm64.whl", hash = "sha256:caaaf598d23e90ac38c571e3ef621c6df7f494fa3ec05ec17ac4ca6d9cc23d53", size = 5896286, upload-time = "2024-12-28T11:19:29.172Z" }, - { url = "https://files.pythonhosted.org/packages/a9/dc/76af9fb2dd5670a3b35b3531c346df9bf23b91d22bef5099e6d2d78c62d3/cpymad-1.17.0-cp310-cp310-macosx_13_0_x86_64.whl", hash = "sha256:414cba8be5dce07b2b0a4159eb0c48b04a3497b8b0edfda7c13c60828f86ad93", size = 5963547, upload-time = "2024-12-28T11:19:31.686Z" }, - { url = "https://files.pythonhosted.org/packages/a1/c9/2d3b1a57aa9d15ae5ff023454139faabf740f575bdbecc653ab481770204/cpymad-1.17.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f44eca4bc69772c5366d46462f7540b9b081e665ce91ffba7bc4236bdc11db82", size = 5855680, upload-time = "2024-12-28T11:19:34.405Z" }, - { url = "https://files.pythonhosted.org/packages/36/ac/06f531b5ee15768b4ef47c7a570ead50942da685cb09624094a5abac38b9/cpymad-1.17.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:30c882b80d8b34f222645abd2a7060d581747a6ef3a98bc5425efbf04d889492", size = 6416603, upload-time = "2024-12-28T11:19:38.219Z" }, - { url = "https://files.pythonhosted.org/packages/26/35/e7e7a75d35c9200697481638cf39aa0e6c8b060365e16127ca447ef277bd/cpymad-1.17.0-cp310-cp310-win_amd64.whl", hash = "sha256:036564a12912d312e12a91f81e500e4d4adca670000f95d917e94e902e738727", size = 5204183, upload-time = "2024-12-28T11:19:41.581Z" }, { url = "https://files.pythonhosted.org/packages/8d/1c/a96f34b248b8fa468ef8b38a29960f74dface0a6bd27b68e22e9cf83da5d/cpymad-1.17.0-cp311-cp311-macosx_13_0_arm64.whl", hash = "sha256:0a2bbcea6bc30dc66d6b4c25245452ea1e922e1aa19cc7fc6ee5b60fe8885e93", size = 5898270, upload-time = "2024-12-28T11:19:43.978Z" }, { url = "https://files.pythonhosted.org/packages/f9/62/9ad02b95e481aa779f821a44102ce57497923613b171563ec1f340737ea8/cpymad-1.17.0-cp311-cp311-macosx_13_0_universal2.whl", hash = "sha256:0f2a1e285c639fe2bed49d9dbab79c0325c14e235e7ae3e1e0f09e12ace51d73", size = 6114598, upload-time = "2024-12-28T11:19:46.086Z" }, { url = "https://files.pythonhosted.org/packages/5f/99/61b64e0e5636d21a89f65c79083ce2e49112140628bb8bed2bda9d7a8050/cpymad-1.17.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5b780d34deaa50e3cba5b72d75f0ee90d2b5b843ac0fff4368964c601a8b2a22", size = 5946779, upload-time = "2024-12-28T11:19:47.978Z" }, @@ -371,18 +317,6 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/8f/d7/9322c609343d929e75e7e5e6255e614fcc67572cfd083959cdef3b7aad79/docutils-0.21.2-py3-none-any.whl", hash = "sha256:dafca5b9e384f0e419294eb4d2ff9fa826435bf15f15b7bd45723e8ad76811b2", size = 587408, upload-time = "2024-04-23T18:57:14.835Z" }, ] -[[package]] -name = "exceptiongroup" -version = "1.3.0" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "typing-extensions", marker = "python_full_version < '3.11'" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/0b/9f/a65090624ecf468cdca03533906e7c69ed7588582240cfe7cc9e770b50eb/exceptiongroup-1.3.0.tar.gz", hash = "sha256:b241f5885f560bc56a59ee63ca4c6a8bfa46ae4ad651af316d4e81817bb9fd88", size = 29749, upload-time = "2025-05-10T17:42:51.123Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/36/f4/c6e662dade71f56cd2f3735141b265c3c79293c109549c1e6933b0651ffc/exceptiongroup-1.3.0-py3-none-any.whl", hash = "sha256:4d111e6e0c13d0644cad6ddaa7ed0261a0b36971f6d23e7ec9b4b9097da78a10", size = 16674, upload-time = "2025-05-10T17:42:49.33Z" }, -] - [[package]] name = "execnet" version = "2.1.1" @@ -407,14 +341,6 @@ version = "4.58.4" source = { registry = "https://pypi.org/simple" } sdist = { url = "https://files.pythonhosted.org/packages/2e/5a/1124b2c8cb3a8015faf552e92714040bcdbc145dfa29928891b02d147a18/fonttools-4.58.4.tar.gz", hash = "sha256:928a8009b9884ed3aae17724b960987575155ca23c6f0b8146e400cc9e0d44ba", size = 3525026, upload-time = "2025-06-13T17:25:15.426Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/ed/86/d22c24caa574449b56e994ed1a96d23b23af85557fb62a92df96439d3f6c/fonttools-4.58.4-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:834542f13fee7625ad753b2db035edb674b07522fcbdd0ed9e9a9e2a1034467f", size = 2748349, upload-time = "2025-06-13T17:23:49.179Z" }, - { url = "https://files.pythonhosted.org/packages/f9/b8/384aca93856def00e7de30341f1e27f439694857d82c35d74a809c705ed0/fonttools-4.58.4-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:2e6c61ce330142525296170cd65666e46121fc0d44383cbbcfa39cf8f58383df", size = 2318565, upload-time = "2025-06-13T17:23:52.144Z" }, - { url = "https://files.pythonhosted.org/packages/1a/f2/273edfdc8d9db89ecfbbf659bd894f7e07b6d53448b19837a4bdba148d17/fonttools-4.58.4-cp310-cp310-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:e9c75f8faa29579c0fbf29b56ae6a3660c6c025f3b671803cb6a9caa7e4e3a98", size = 4838855, upload-time = "2025-06-13T17:23:54.039Z" }, - { url = "https://files.pythonhosted.org/packages/13/fa/403703548c093c30b52ab37e109b369558afa221130e67f06bef7513f28a/fonttools-4.58.4-cp310-cp310-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:88dedcedbd5549e35b2ea3db3de02579c27e62e51af56779c021e7b33caadd0e", size = 4767637, upload-time = "2025-06-13T17:23:56.17Z" }, - { url = "https://files.pythonhosted.org/packages/6e/a8/3380e1e0bff6defb0f81c9abf274a5b4a0f30bc8cab4fd4e346c6f923b4c/fonttools-4.58.4-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:ae80a895adab43586f4da1521d58fd4f4377cef322ee0cc205abcefa3a5effc3", size = 4819397, upload-time = "2025-06-13T17:23:58.263Z" }, - { url = "https://files.pythonhosted.org/packages/cd/1b/99e47eb17a8ca51d808622a4658584fa8f340857438a4e9d7ac326d4a041/fonttools-4.58.4-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:0d3acc7f0d151da116e87a182aefb569cf0a3c8e0fd4c9cd0a7c1e7d3e7adb26", size = 4926641, upload-time = "2025-06-13T17:24:00.368Z" }, - { url = "https://files.pythonhosted.org/packages/31/75/415254408f038e35b36c8525fc31feb8561f98445688dd2267c23eafd7a2/fonttools-4.58.4-cp310-cp310-win32.whl", hash = "sha256:1244f69686008e7e8d2581d9f37eef330a73fee3843f1107993eb82c9d306577", size = 2201917, upload-time = "2025-06-13T17:24:02.587Z" }, - { url = "https://files.pythonhosted.org/packages/c5/69/f019a15ed2946317c5318e1bcc8876f8a54a313848604ad1d4cfc4c07916/fonttools-4.58.4-cp310-cp310-win_amd64.whl", hash = "sha256:2a66c0af8a01eb2b78645af60f3b787de5fe5eb1fd8348163715b80bdbfbde1f", size = 2246327, upload-time = "2025-06-13T17:24:04.087Z" }, { url = "https://files.pythonhosted.org/packages/17/7b/cc6e9bb41bab223bd2dc70ba0b21386b85f604e27f4c3206b4205085a2ab/fonttools-4.58.4-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:a3841991c9ee2dc0562eb7f23d333d34ce81e8e27c903846f0487da21e0028eb", size = 2768901, upload-time = "2025-06-13T17:24:05.901Z" }, { url = "https://files.pythonhosted.org/packages/3d/15/98d75df9f2b4e7605f3260359ad6e18e027c11fa549f74fce567270ac891/fonttools-4.58.4-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:3c98f91b6a9604e7ffb5ece6ea346fa617f967c2c0944228801246ed56084664", size = 2328696, upload-time = "2025-06-13T17:24:09.18Z" }, { url = "https://files.pythonhosted.org/packages/a8/c8/dc92b80f5452c9c40164e01b3f78f04b835a00e673bd9355ca257008ff61/fonttools-4.58.4-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:ab9f891eb687ddf6a4e5f82901e00f992e18012ca97ab7acd15f13632acd14c1", size = 5018830, upload-time = "2025-06-13T17:24:11.282Z" }, @@ -496,21 +422,6 @@ version = "1.4.8" source = { registry = "https://pypi.org/simple" } sdist = { url = "https://files.pythonhosted.org/packages/82/59/7c91426a8ac292e1cdd53a63b6d9439abd573c875c3f92c146767dd33faf/kiwisolver-1.4.8.tar.gz", hash = "sha256:23d5f023bdc8c7e54eb65f03ca5d5bb25b601eac4d7f1a042888a1f45237987e", size = 97538, upload-time = "2024-12-24T18:30:51.519Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/47/5f/4d8e9e852d98ecd26cdf8eaf7ed8bc33174033bba5e07001b289f07308fd/kiwisolver-1.4.8-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:88c6f252f6816a73b1f8c904f7bbe02fd67c09a69f7cb8a0eecdbf5ce78e63db", size = 124623, upload-time = "2024-12-24T18:28:17.687Z" }, - { url = "https://files.pythonhosted.org/packages/1d/70/7f5af2a18a76fe92ea14675f8bd88ce53ee79e37900fa5f1a1d8e0b42998/kiwisolver-1.4.8-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:c72941acb7b67138f35b879bbe85be0f6c6a70cab78fe3ef6db9c024d9223e5b", size = 66720, upload-time = "2024-12-24T18:28:19.158Z" }, - { url = "https://files.pythonhosted.org/packages/c6/13/e15f804a142353aefd089fadc8f1d985561a15358c97aca27b0979cb0785/kiwisolver-1.4.8-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:ce2cf1e5688edcb727fdf7cd1bbd0b6416758996826a8be1d958f91880d0809d", size = 65413, upload-time = "2024-12-24T18:28:20.064Z" }, - { url = "https://files.pythonhosted.org/packages/ce/6d/67d36c4d2054e83fb875c6b59d0809d5c530de8148846b1370475eeeece9/kiwisolver-1.4.8-cp310-cp310-manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:c8bf637892dc6e6aad2bc6d4d69d08764166e5e3f69d469e55427b6ac001b19d", size = 1650826, upload-time = "2024-12-24T18:28:21.203Z" }, - { url = "https://files.pythonhosted.org/packages/de/c6/7b9bb8044e150d4d1558423a1568e4f227193662a02231064e3824f37e0a/kiwisolver-1.4.8-cp310-cp310-manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:034d2c891f76bd3edbdb3ea11140d8510dca675443da7304205a2eaa45d8334c", size = 1628231, upload-time = "2024-12-24T18:28:23.851Z" }, - { url = "https://files.pythonhosted.org/packages/b6/38/ad10d437563063eaaedbe2c3540a71101fc7fb07a7e71f855e93ea4de605/kiwisolver-1.4.8-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d47b28d1dfe0793d5e96bce90835e17edf9a499b53969b03c6c47ea5985844c3", size = 1408938, upload-time = "2024-12-24T18:28:26.687Z" }, - { url = "https://files.pythonhosted.org/packages/52/ce/c0106b3bd7f9e665c5f5bc1e07cc95b5dabd4e08e3dad42dbe2faad467e7/kiwisolver-1.4.8-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:eb158fe28ca0c29f2260cca8c43005329ad58452c36f0edf298204de32a9a3ed", size = 1422799, upload-time = "2024-12-24T18:28:30.538Z" }, - { url = "https://files.pythonhosted.org/packages/d0/87/efb704b1d75dc9758087ba374c0f23d3254505edaedd09cf9d247f7878b9/kiwisolver-1.4.8-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:d5536185fce131780ebd809f8e623bf4030ce1b161353166c49a3c74c287897f", size = 1354362, upload-time = "2024-12-24T18:28:32.943Z" }, - { url = "https://files.pythonhosted.org/packages/eb/b3/fd760dc214ec9a8f208b99e42e8f0130ff4b384eca8b29dd0efc62052176/kiwisolver-1.4.8-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:369b75d40abedc1da2c1f4de13f3482cb99e3237b38726710f4a793432b1c5ff", size = 2222695, upload-time = "2024-12-24T18:28:35.641Z" }, - { url = "https://files.pythonhosted.org/packages/a2/09/a27fb36cca3fc01700687cc45dae7a6a5f8eeb5f657b9f710f788748e10d/kiwisolver-1.4.8-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:641f2ddf9358c80faa22e22eb4c9f54bd3f0e442e038728f500e3b978d00aa7d", size = 2370802, upload-time = "2024-12-24T18:28:38.357Z" }, - { url = "https://files.pythonhosted.org/packages/3d/c3/ba0a0346db35fe4dc1f2f2cf8b99362fbb922d7562e5f911f7ce7a7b60fa/kiwisolver-1.4.8-cp310-cp310-musllinux_1_2_ppc64le.whl", hash = "sha256:d561d2d8883e0819445cfe58d7ddd673e4015c3c57261d7bdcd3710d0d14005c", size = 2334646, upload-time = "2024-12-24T18:28:40.941Z" }, - { url = "https://files.pythonhosted.org/packages/41/52/942cf69e562f5ed253ac67d5c92a693745f0bed3c81f49fc0cbebe4d6b00/kiwisolver-1.4.8-cp310-cp310-musllinux_1_2_s390x.whl", hash = "sha256:1732e065704b47c9afca7ffa272f845300a4eb959276bf6970dc07265e73b605", size = 2467260, upload-time = "2024-12-24T18:28:42.273Z" }, - { url = "https://files.pythonhosted.org/packages/32/26/2d9668f30d8a494b0411d4d7d4ea1345ba12deb6a75274d58dd6ea01e951/kiwisolver-1.4.8-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:bcb1ebc3547619c3b58a39e2448af089ea2ef44b37988caf432447374941574e", size = 2288633, upload-time = "2024-12-24T18:28:44.87Z" }, - { url = "https://files.pythonhosted.org/packages/98/99/0dd05071654aa44fe5d5e350729961e7bb535372935a45ac89a8924316e6/kiwisolver-1.4.8-cp310-cp310-win_amd64.whl", hash = "sha256:89c107041f7b27844179ea9c85d6da275aa55ecf28413e87624d033cf1f6b751", size = 71885, upload-time = "2024-12-24T18:28:47.346Z" }, - { url = "https://files.pythonhosted.org/packages/6c/fc/822e532262a97442989335394d441cd1d0448c2e46d26d3e04efca84df22/kiwisolver-1.4.8-cp310-cp310-win_arm64.whl", hash = "sha256:b5773efa2be9eb9fcf5415ea3ab70fc785d598729fd6057bea38d539ead28271", size = 65175, upload-time = "2024-12-24T18:28:49.651Z" }, { url = "https://files.pythonhosted.org/packages/da/ed/c913ee28936c371418cb167b128066ffb20bbf37771eecc2c97edf8a6e4c/kiwisolver-1.4.8-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:a4d3601908c560bdf880f07d94f31d734afd1bb71e96585cace0e38ef44c6d84", size = 124635, upload-time = "2024-12-24T18:28:51.826Z" }, { url = "https://files.pythonhosted.org/packages/4c/45/4a7f896f7467aaf5f56ef093d1f329346f3b594e77c6a3c327b2d415f521/kiwisolver-1.4.8-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:856b269c4d28a5c0d5e6c1955ec36ebfd1651ac00e1ce0afa3e28da95293b561", size = 66717, upload-time = "2024-12-24T18:28:54.256Z" }, { url = "https://files.pythonhosted.org/packages/5f/b4/c12b3ac0852a3a68f94598d4c8d569f55361beef6159dce4e7b624160da2/kiwisolver-1.4.8-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:c2b9a96e0f326205af81a15718a9073328df1173a2619a68553decb7097fd5d7", size = 65413, upload-time = "2024-12-24T18:28:55.184Z" }, @@ -569,12 +480,6 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/05/f9/27e94c1b3eb29e6933b6986ffc5fa1177d2cd1f0c8efc5f02c91c9ac61de/kiwisolver-1.4.8-cp313-cp313t-musllinux_1_2_ppc64le.whl", hash = "sha256:151dffc4865e5fe6dafce5480fab84f950d14566c480c08a53c663a0020504b6", size = 2390661, upload-time = "2024-12-24T18:30:34.939Z" }, { url = "https://files.pythonhosted.org/packages/d9/d4/3c9735faa36ac591a4afcc2980d2691000506050b7a7e80bcfe44048daa7/kiwisolver-1.4.8-cp313-cp313t-musllinux_1_2_s390x.whl", hash = "sha256:577facaa411c10421314598b50413aa1ebcf5126f704f1e5d72d7e4e9f020d90", size = 2546710, upload-time = "2024-12-24T18:30:37.281Z" }, { url = "https://files.pythonhosted.org/packages/4c/fa/be89a49c640930180657482a74970cdcf6f7072c8d2471e1babe17a222dc/kiwisolver-1.4.8-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:be4816dc51c8a471749d664161b434912eee82f2ea66bd7628bd14583a833e85", size = 2349213, upload-time = "2024-12-24T18:30:40.019Z" }, - { url = "https://files.pythonhosted.org/packages/1f/f9/ae81c47a43e33b93b0a9819cac6723257f5da2a5a60daf46aa5c7226ea85/kiwisolver-1.4.8-pp310-pypy310_pp73-macosx_10_15_x86_64.whl", hash = "sha256:e7a019419b7b510f0f7c9dceff8c5eae2392037eae483a7f9162625233802b0a", size = 60403, upload-time = "2024-12-24T18:30:41.372Z" }, - { url = "https://files.pythonhosted.org/packages/58/ca/f92b5cb6f4ce0c1ebfcfe3e2e42b96917e16f7090e45b21102941924f18f/kiwisolver-1.4.8-pp310-pypy310_pp73-macosx_11_0_arm64.whl", hash = "sha256:286b18e86682fd2217a48fc6be6b0f20c1d0ed10958d8dc53453ad58d7be0bf8", size = 58657, upload-time = "2024-12-24T18:30:42.392Z" }, - { url = "https://files.pythonhosted.org/packages/80/28/ae0240f732f0484d3a4dc885d055653c47144bdf59b670aae0ec3c65a7c8/kiwisolver-1.4.8-pp310-pypy310_pp73-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:4191ee8dfd0be1c3666ccbac178c5a05d5f8d689bbe3fc92f3c4abec817f8fe0", size = 84948, upload-time = "2024-12-24T18:30:44.703Z" }, - { url = "https://files.pythonhosted.org/packages/5d/eb/78d50346c51db22c7203c1611f9b513075f35c4e0e4877c5dde378d66043/kiwisolver-1.4.8-pp310-pypy310_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:7cd2785b9391f2873ad46088ed7599a6a71e762e1ea33e87514b1a441ed1da1c", size = 81186, upload-time = "2024-12-24T18:30:45.654Z" }, - { url = "https://files.pythonhosted.org/packages/43/f8/7259f18c77adca88d5f64f9a522792e178b2691f3748817a8750c2d216ef/kiwisolver-1.4.8-pp310-pypy310_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c07b29089b7ba090b6f1a669f1411f27221c3662b3a1b7010e67b59bb5a6f10b", size = 80279, upload-time = "2024-12-24T18:30:47.951Z" }, - { url = "https://files.pythonhosted.org/packages/3a/1d/50ad811d1c5dae091e4cf046beba925bcae0a610e79ae4c538f996f63ed5/kiwisolver-1.4.8-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:65ea09a5a3faadd59c2ce96dc7bf0f364986a315949dc6374f04396b0d60e09b", size = 71762, upload-time = "2024-12-24T18:30:48.903Z" }, ] [[package]] @@ -592,11 +497,6 @@ version = "0.44.0" source = { registry = "https://pypi.org/simple" } sdist = { url = "https://files.pythonhosted.org/packages/89/6a/95a3d3610d5c75293d5dbbb2a76480d5d4eeba641557b69fe90af6c5b84e/llvmlite-0.44.0.tar.gz", hash = "sha256:07667d66a5d150abed9157ab6c0b9393c9356f229784a4385c02f99e94fc94d4", size = 171880, upload-time = "2025-01-20T11:14:41.342Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/41/75/d4863ddfd8ab5f6e70f4504cf8cc37f4e986ec6910f4ef8502bb7d3c1c71/llvmlite-0.44.0-cp310-cp310-macosx_10_14_x86_64.whl", hash = "sha256:9fbadbfba8422123bab5535b293da1cf72f9f478a65645ecd73e781f962ca614", size = 28132306, upload-time = "2025-01-20T11:12:18.634Z" }, - { url = "https://files.pythonhosted.org/packages/37/d9/6e8943e1515d2f1003e8278819ec03e4e653e2eeb71e4d00de6cfe59424e/llvmlite-0.44.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:cccf8eb28f24840f2689fb1a45f9c0f7e582dd24e088dcf96e424834af11f791", size = 26201096, upload-time = "2025-01-20T11:12:24.544Z" }, - { url = "https://files.pythonhosted.org/packages/aa/46/8ffbc114def88cc698906bf5acab54ca9fdf9214fe04aed0e71731fb3688/llvmlite-0.44.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7202b678cdf904823c764ee0fe2dfe38a76981f4c1e51715b4cb5abb6cf1d9e8", size = 42361859, upload-time = "2025-01-20T11:12:31.839Z" }, - { url = "https://files.pythonhosted.org/packages/30/1c/9366b29ab050a726af13ebaae8d0dff00c3c58562261c79c635ad4f5eb71/llvmlite-0.44.0-cp310-cp310-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:40526fb5e313d7b96bda4cbb2c85cd5374e04d80732dd36a282d72a560bb6408", size = 41184199, upload-time = "2025-01-20T11:12:40.049Z" }, - { url = "https://files.pythonhosted.org/packages/69/07/35e7c594b021ecb1938540f5bce543ddd8713cff97f71d81f021221edc1b/llvmlite-0.44.0-cp310-cp310-win_amd64.whl", hash = "sha256:41e3839150db4330e1b2716c0be3b5c4672525b4c9005e17c7597f835f351ce2", size = 30332381, upload-time = "2025-01-20T11:12:47.054Z" }, { url = "https://files.pythonhosted.org/packages/b5/e2/86b245397052386595ad726f9742e5223d7aea999b18c518a50e96c3aca4/llvmlite-0.44.0-cp311-cp311-macosx_10_14_x86_64.whl", hash = "sha256:eed7d5f29136bda63b6d7804c279e2b72e08c952b7c5df61f45db408e0ee52f3", size = 28132305, upload-time = "2025-01-20T11:12:53.936Z" }, { url = "https://files.pythonhosted.org/packages/ff/ec/506902dc6870249fbe2466d9cf66d531265d0f3a1157213c8f986250c033/llvmlite-0.44.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:ace564d9fa44bb91eb6e6d8e7754977783c68e90a471ea7ce913bff30bd62427", size = 26201090, upload-time = "2025-01-20T11:12:59.847Z" }, { url = "https://files.pythonhosted.org/packages/99/fe/d030f1849ebb1f394bb3f7adad5e729b634fb100515594aca25c354ffc62/llvmlite-0.44.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c5d22c3bfc842668168a786af4205ec8e3ad29fb1bc03fd11fd48460d0df64c1", size = 42361858, upload-time = "2025-01-20T11:13:07.623Z" }, @@ -645,16 +545,6 @@ version = "3.0.2" source = { registry = "https://pypi.org/simple" } sdist = { url = "https://files.pythonhosted.org/packages/b2/97/5d42485e71dfc078108a86d6de8fa46db44a1a9295e89c5d6d4a06e23a62/markupsafe-3.0.2.tar.gz", hash = "sha256:ee55d3edf80167e48ea11a923c7386f4669df67d7994554387f84e7d8b0a2bf0", size = 20537, upload-time = "2024-10-18T15:21:54.129Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/04/90/d08277ce111dd22f77149fd1a5d4653eeb3b3eaacbdfcbae5afb2600eebd/MarkupSafe-3.0.2-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:7e94c425039cde14257288fd61dcfb01963e658efbc0ff54f5306b06054700f8", size = 14357, upload-time = "2024-10-18T15:20:51.44Z" }, - { url = "https://files.pythonhosted.org/packages/04/e1/6e2194baeae0bca1fae6629dc0cbbb968d4d941469cbab11a3872edff374/MarkupSafe-3.0.2-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:9e2d922824181480953426608b81967de705c3cef4d1af983af849d7bd619158", size = 12393, upload-time = "2024-10-18T15:20:52.426Z" }, - { url = "https://files.pythonhosted.org/packages/1d/69/35fa85a8ece0a437493dc61ce0bb6d459dcba482c34197e3efc829aa357f/MarkupSafe-3.0.2-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:38a9ef736c01fccdd6600705b09dc574584b89bea478200c5fbf112a6b0d5579", size = 21732, upload-time = "2024-10-18T15:20:53.578Z" }, - { url = "https://files.pythonhosted.org/packages/22/35/137da042dfb4720b638d2937c38a9c2df83fe32d20e8c8f3185dbfef05f7/MarkupSafe-3.0.2-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:bbcb445fa71794da8f178f0f6d66789a28d7319071af7a496d4d507ed566270d", size = 20866, upload-time = "2024-10-18T15:20:55.06Z" }, - { url = "https://files.pythonhosted.org/packages/29/28/6d029a903727a1b62edb51863232152fd335d602def598dade38996887f0/MarkupSafe-3.0.2-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:57cb5a3cf367aeb1d316576250f65edec5bb3be939e9247ae594b4bcbc317dfb", size = 20964, upload-time = "2024-10-18T15:20:55.906Z" }, - { url = "https://files.pythonhosted.org/packages/cc/cd/07438f95f83e8bc028279909d9c9bd39e24149b0d60053a97b2bc4f8aa51/MarkupSafe-3.0.2-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:3809ede931876f5b2ec92eef964286840ed3540dadf803dd570c3b7e13141a3b", size = 21977, upload-time = "2024-10-18T15:20:57.189Z" }, - { url = "https://files.pythonhosted.org/packages/29/01/84b57395b4cc062f9c4c55ce0df7d3108ca32397299d9df00fedd9117d3d/MarkupSafe-3.0.2-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:e07c3764494e3776c602c1e78e298937c3315ccc9043ead7e685b7f2b8d47b3c", size = 21366, upload-time = "2024-10-18T15:20:58.235Z" }, - { url = "https://files.pythonhosted.org/packages/bd/6e/61ebf08d8940553afff20d1fb1ba7294b6f8d279df9fd0c0db911b4bbcfd/MarkupSafe-3.0.2-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:b424c77b206d63d500bcb69fa55ed8d0e6a3774056bdc4839fc9298a7edca171", size = 21091, upload-time = "2024-10-18T15:20:59.235Z" }, - { url = "https://files.pythonhosted.org/packages/11/23/ffbf53694e8c94ebd1e7e491de185124277964344733c45481f32ede2499/MarkupSafe-3.0.2-cp310-cp310-win32.whl", hash = "sha256:fcabf5ff6eea076f859677f5f0b6b5c1a51e70a376b0579e0eadef8db48c6b50", size = 15065, upload-time = "2024-10-18T15:21:00.307Z" }, - { url = "https://files.pythonhosted.org/packages/44/06/e7175d06dd6e9172d4a69a72592cb3f7a996a9c396eee29082826449bbc3/MarkupSafe-3.0.2-cp310-cp310-win_amd64.whl", hash = "sha256:6af100e168aa82a50e186c82875a5893c5597a0c1ccdb0d8b40240b1f28b969a", size = 15514, upload-time = "2024-10-18T15:21:01.122Z" }, { url = "https://files.pythonhosted.org/packages/6b/28/bbf83e3f76936960b850435576dd5e67034e200469571be53f69174a2dfd/MarkupSafe-3.0.2-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:9025b4018f3a1314059769c7bf15441064b2207cb3f065e6ea1e7359cb46db9d", size = 14353, upload-time = "2024-10-18T15:21:02.187Z" }, { url = "https://files.pythonhosted.org/packages/6c/30/316d194b093cde57d448a4c3209f22e3046c5bb2fb0820b118292b334be7/MarkupSafe-3.0.2-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:93335ca3812df2f366e80509ae119189886b0f3c2b81325d39efdb84a1e2ae93", size = 12392, upload-time = "2024-10-18T15:21:02.941Z" }, { url = "https://files.pythonhosted.org/packages/f2/96/9cdafba8445d3a53cae530aaf83c38ec64c4d5427d975c974084af5bc5d2/MarkupSafe-3.0.2-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:2cb8438c3cbb25e220c2ab33bb226559e7afb3baec11c4f218ffa7308603c832", size = 23984, upload-time = "2024-10-18T15:21:03.953Z" }, @@ -714,12 +604,6 @@ dependencies = [ ] sdist = { url = "https://files.pythonhosted.org/packages/26/91/d49359a21893183ed2a5b6c76bec40e0b1dcbf8ca148f864d134897cfc75/matplotlib-3.10.3.tar.gz", hash = "sha256:2f82d2c5bb7ae93aaaa4cd42aca65d76ce6376f83304fa3a630b569aca274df0", size = 34799811, upload-time = "2025-05-08T19:10:54.39Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/d0/ea/2bba25d289d389c7451f331ecd593944b3705f06ddf593fa7be75037d308/matplotlib-3.10.3-cp310-cp310-macosx_10_12_x86_64.whl", hash = "sha256:213fadd6348d106ca7db99e113f1bea1e65e383c3ba76e8556ba4a3054b65ae7", size = 8167862, upload-time = "2025-05-08T19:09:39.563Z" }, - { url = "https://files.pythonhosted.org/packages/41/81/cc70b5138c926604e8c9ed810ed4c79e8116ba72e02230852f5c12c87ba2/matplotlib-3.10.3-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:d3bec61cb8221f0ca6313889308326e7bb303d0d302c5cc9e523b2f2e6c73deb", size = 8042149, upload-time = "2025-05-08T19:09:42.413Z" }, - { url = "https://files.pythonhosted.org/packages/4a/9a/0ff45b6bfa42bb16de597e6058edf2361c298ad5ef93b327728145161bbf/matplotlib-3.10.3-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:8c21ae75651c0231b3ba014b6d5e08fb969c40cdb5a011e33e99ed0c9ea86ecb", size = 8453719, upload-time = "2025-05-08T19:09:44.901Z" }, - { url = "https://files.pythonhosted.org/packages/85/c7/1866e972fed6d71ef136efbc980d4d1854ab7ef1ea8152bbd995ca231c81/matplotlib-3.10.3-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a49e39755580b08e30e3620efc659330eac5d6534ab7eae50fa5e31f53ee4e30", size = 8590801, upload-time = "2025-05-08T19:09:47.404Z" }, - { url = "https://files.pythonhosted.org/packages/5d/b9/748f6626d534ab7e255bdc39dc22634d337cf3ce200f261b5d65742044a1/matplotlib-3.10.3-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:cf4636203e1190871d3a73664dea03d26fb019b66692cbfd642faafdad6208e8", size = 9402111, upload-time = "2025-05-08T19:09:49.474Z" }, - { url = "https://files.pythonhosted.org/packages/1f/78/8bf07bd8fb67ea5665a6af188e70b57fcb2ab67057daa06b85a08e59160a/matplotlib-3.10.3-cp310-cp310-win_amd64.whl", hash = "sha256:fd5641a9bb9d55f4dd2afe897a53b537c834b9012684c8444cc105895c8c16fd", size = 8057213, upload-time = "2025-05-08T19:09:51.489Z" }, { url = "https://files.pythonhosted.org/packages/f5/bd/af9f655456f60fe1d575f54fb14704ee299b16e999704817a7645dfce6b0/matplotlib-3.10.3-cp311-cp311-macosx_10_12_x86_64.whl", hash = "sha256:0ef061f74cd488586f552d0c336b2f078d43bc00dc473d2c3e7bfee2272f3fa8", size = 8178873, upload-time = "2025-05-08T19:09:53.857Z" }, { url = "https://files.pythonhosted.org/packages/c2/86/e1c86690610661cd716eda5f9d0b35eaf606ae6c9b6736687cfc8f2d0cd8/matplotlib-3.10.3-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:d96985d14dc5f4a736bbea4b9de9afaa735f8a0fc2ca75be2fa9e96b2097369d", size = 8052205, upload-time = "2025-05-08T19:09:55.684Z" }, { url = "https://files.pythonhosted.org/packages/54/51/a9f8e49af3883dacddb2da1af5fca1f7468677f1188936452dd9aaaeb9ed/matplotlib-3.10.3-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:7c5f0283da91e9522bdba4d6583ed9d5521566f63729ffb68334f86d0bb98049", size = 8465823, upload-time = "2025-05-08T19:09:57.442Z" }, @@ -744,9 +628,6 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/ba/c7/473bc559beec08ebee9f86ca77a844b65747e1a6c2691e8c92e40b9f42a8/matplotlib-3.10.3-cp313-cp313t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f6929fc618cb6db9cb75086f73b3219bbb25920cb24cee2ea7a12b04971a4158", size = 8618082, upload-time = "2025-05-08T19:10:39.892Z" }, { url = "https://files.pythonhosted.org/packages/d8/e9/6ce8edd264c8819e37bbed8172e0ccdc7107fe86999b76ab5752276357a4/matplotlib-3.10.3-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:6c7818292a5cc372a2dc4c795e5c356942eb8350b98ef913f7fda51fe175ac5d", size = 9413699, upload-time = "2025-05-08T19:10:42.376Z" }, { url = "https://files.pythonhosted.org/packages/1b/92/9a45c91089c3cf690b5badd4be81e392ff086ccca8a1d4e3a08463d8a966/matplotlib-3.10.3-cp313-cp313t-win_amd64.whl", hash = "sha256:4f23ffe95c5667ef8a2b56eea9b53db7f43910fa4a2d5472ae0f72b64deab4d5", size = 8139044, upload-time = "2025-05-08T19:10:44.551Z" }, - { url = "https://files.pythonhosted.org/packages/3d/d1/f54d43e95384b312ffa4a74a4326c722f3b8187aaaa12e9a84cdf3037131/matplotlib-3.10.3-pp310-pypy310_pp73-macosx_10_15_x86_64.whl", hash = "sha256:86ab63d66bbc83fdb6733471d3bff40897c1e9921cba112accd748eee4bce5e4", size = 8162896, upload-time = "2025-05-08T19:10:46.432Z" }, - { url = "https://files.pythonhosted.org/packages/24/a4/fbfc00c2346177c95b353dcf9b5a004106abe8730a62cb6f27e79df0a698/matplotlib-3.10.3-pp310-pypy310_pp73-macosx_11_0_arm64.whl", hash = "sha256:a48f9c08bf7444b5d2391a83e75edb464ccda3c380384b36532a0962593a1751", size = 8039702, upload-time = "2025-05-08T19:10:49.634Z" }, - { url = "https://files.pythonhosted.org/packages/6a/b9/59e120d24a2ec5fc2d30646adb2efb4621aab3c6d83d66fb2a7a182db032/matplotlib-3.10.3-pp310-pypy310_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:cb73d8aa75a237457988f9765e4dfe1c0d2453c5ca4eabc897d4309672c8e014", size = 8594298, upload-time = "2025-05-08T19:10:51.738Z" }, ] [[package]] @@ -777,11 +658,6 @@ dependencies = [ ] sdist = { url = "https://files.pythonhosted.org/packages/1c/a0/e21f57604304aa03ebb8e098429222722ad99176a4f979d34af1d1ee80da/numba-0.61.2.tar.gz", hash = "sha256:8750ee147940a6637b80ecf7f95062185ad8726c8c28a2295b8ec1160a196f7d", size = 2820615, upload-time = "2025-04-09T02:58:07.659Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/eb/ca/f470be59552ccbf9531d2d383b67ae0b9b524d435fb4a0d229fef135116e/numba-0.61.2-cp310-cp310-macosx_10_14_x86_64.whl", hash = "sha256:cf9f9fc00d6eca0c23fc840817ce9f439b9f03c8f03d6246c0e7f0cb15b7162a", size = 2775663, upload-time = "2025-04-09T02:57:34.143Z" }, - { url = "https://files.pythonhosted.org/packages/f5/13/3bdf52609c80d460a3b4acfb9fdb3817e392875c0d6270cf3fd9546f138b/numba-0.61.2-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:ea0247617edcb5dd61f6106a56255baab031acc4257bddaeddb3a1003b4ca3fd", size = 2778344, upload-time = "2025-04-09T02:57:36.609Z" }, - { url = "https://files.pythonhosted.org/packages/e2/7d/bfb2805bcfbd479f04f835241ecf28519f6e3609912e3a985aed45e21370/numba-0.61.2-cp310-cp310-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:ae8c7a522c26215d5f62ebec436e3d341f7f590079245a2f1008dfd498cc1642", size = 3824054, upload-time = "2025-04-09T02:57:38.162Z" }, - { url = "https://files.pythonhosted.org/packages/e3/27/797b2004745c92955470c73c82f0e300cf033c791f45bdecb4b33b12bdea/numba-0.61.2-cp310-cp310-manylinux_2_28_aarch64.whl", hash = "sha256:bd1e74609855aa43661edffca37346e4e8462f6903889917e9f41db40907daa2", size = 3518531, upload-time = "2025-04-09T02:57:39.709Z" }, - { url = "https://files.pythonhosted.org/packages/b1/c6/c2fb11e50482cb310afae87a997707f6c7d8a48967b9696271347441f650/numba-0.61.2-cp310-cp310-win_amd64.whl", hash = "sha256:ae45830b129c6137294093b269ef0a22998ccc27bf7cf096ab8dcf7bca8946f9", size = 2831612, upload-time = "2025-04-09T02:57:41.559Z" }, { url = "https://files.pythonhosted.org/packages/3f/97/c99d1056aed767503c228f7099dc11c402906b42a4757fec2819329abb98/numba-0.61.2-cp311-cp311-macosx_10_14_x86_64.whl", hash = "sha256:efd3db391df53aaa5cfbee189b6c910a5b471488749fd6606c3f33fc984c2ae2", size = 2775825, upload-time = "2025-04-09T02:57:43.442Z" }, { url = "https://files.pythonhosted.org/packages/95/9e/63c549f37136e892f006260c3e2613d09d5120672378191f2dc387ba65a2/numba-0.61.2-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:49c980e4171948ffebf6b9a2520ea81feed113c1f4890747ba7f59e74be84b1b", size = 2778695, upload-time = "2025-04-09T02:57:44.968Z" }, { url = "https://files.pythonhosted.org/packages/97/c8/8740616c8436c86c1b9a62e72cb891177d2c34c2d24ddcde4c390371bf4c/numba-0.61.2-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:3945615cd73c2c7eba2a85ccc9c1730c21cd3958bfcf5a44302abae0fb07bb60", size = 3829227, upload-time = "2025-04-09T02:57:46.63Z" }, @@ -805,16 +681,6 @@ version = "2.2.6" source = { registry = "https://pypi.org/simple" } sdist = { url = "https://files.pythonhosted.org/packages/76/21/7d2a95e4bba9dc13d043ee156a356c0a8f0c6309dff6b21b4d71a073b8a8/numpy-2.2.6.tar.gz", hash = "sha256:e29554e2bef54a90aa5cc07da6ce955accb83f21ab5de01a62c8478897b264fd", size = 20276440, upload-time = "2025-05-17T22:38:04.611Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/9a/3e/ed6db5be21ce87955c0cbd3009f2803f59fa08df21b5df06862e2d8e2bdd/numpy-2.2.6-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:b412caa66f72040e6d268491a59f2c43bf03eb6c96dd8f0307829feb7fa2b6fb", size = 21165245, upload-time = "2025-05-17T21:27:58.555Z" }, - { url = "https://files.pythonhosted.org/packages/22/c2/4b9221495b2a132cc9d2eb862e21d42a009f5a60e45fc44b00118c174bff/numpy-2.2.6-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:8e41fd67c52b86603a91c1a505ebaef50b3314de0213461c7a6e99c9a3beff90", size = 14360048, upload-time = "2025-05-17T21:28:21.406Z" }, - { url = "https://files.pythonhosted.org/packages/fd/77/dc2fcfc66943c6410e2bf598062f5959372735ffda175b39906d54f02349/numpy-2.2.6-cp310-cp310-macosx_14_0_arm64.whl", hash = "sha256:37e990a01ae6ec7fe7fa1c26c55ecb672dd98b19c3d0e1d1f326fa13cb38d163", size = 5340542, upload-time = "2025-05-17T21:28:30.931Z" }, - { url = "https://files.pythonhosted.org/packages/7a/4f/1cb5fdc353a5f5cc7feb692db9b8ec2c3d6405453f982435efc52561df58/numpy-2.2.6-cp310-cp310-macosx_14_0_x86_64.whl", hash = "sha256:5a6429d4be8ca66d889b7cf70f536a397dc45ba6faeb5f8c5427935d9592e9cf", size = 6878301, upload-time = "2025-05-17T21:28:41.613Z" }, - { url = "https://files.pythonhosted.org/packages/eb/17/96a3acd228cec142fcb8723bd3cc39c2a474f7dcf0a5d16731980bcafa95/numpy-2.2.6-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:efd28d4e9cd7d7a8d39074a4d44c63eda73401580c5c76acda2ce969e0a38e83", size = 14297320, upload-time = "2025-05-17T21:29:02.78Z" }, - { url = "https://files.pythonhosted.org/packages/b4/63/3de6a34ad7ad6646ac7d2f55ebc6ad439dbbf9c4370017c50cf403fb19b5/numpy-2.2.6-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:fc7b73d02efb0e18c000e9ad8b83480dfcd5dfd11065997ed4c6747470ae8915", size = 16801050, upload-time = "2025-05-17T21:29:27.675Z" }, - { url = "https://files.pythonhosted.org/packages/07/b6/89d837eddef52b3d0cec5c6ba0456c1bf1b9ef6a6672fc2b7873c3ec4e2e/numpy-2.2.6-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:74d4531beb257d2c3f4b261bfb0fc09e0f9ebb8842d82a7b4209415896adc680", size = 15807034, upload-time = "2025-05-17T21:29:51.102Z" }, - { url = "https://files.pythonhosted.org/packages/01/c8/dc6ae86e3c61cfec1f178e5c9f7858584049b6093f843bca541f94120920/numpy-2.2.6-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:8fc377d995680230e83241d8a96def29f204b5782f371c532579b4f20607a289", size = 18614185, upload-time = "2025-05-17T21:30:18.703Z" }, - { url = "https://files.pythonhosted.org/packages/5b/c5/0064b1b7e7c89137b471ccec1fd2282fceaae0ab3a9550f2568782d80357/numpy-2.2.6-cp310-cp310-win32.whl", hash = "sha256:b093dd74e50a8cba3e873868d9e93a85b78e0daf2e98c6797566ad8044e8363d", size = 6527149, upload-time = "2025-05-17T21:30:29.788Z" }, - { url = "https://files.pythonhosted.org/packages/a3/dd/4b822569d6b96c39d1215dbae0582fd99954dcbcf0c1a13c61783feaca3f/numpy-2.2.6-cp310-cp310-win_amd64.whl", hash = "sha256:f0fd6321b839904e15c46e0d257fdd101dd7f530fe03fd6359c1ea63738703f3", size = 12904620, upload-time = "2025-05-17T21:30:48.994Z" }, { url = "https://files.pythonhosted.org/packages/da/a8/4f83e2aa666a9fbf56d6118faaaf5f1974d456b1823fda0a176eff722839/numpy-2.2.6-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:f9f1adb22318e121c5c69a09142811a201ef17ab257a1e66ca3025065b7f53ae", size = 21176963, upload-time = "2025-05-17T21:31:19.36Z" }, { url = "https://files.pythonhosted.org/packages/b3/2b/64e1affc7972decb74c9e29e5649fac940514910960ba25cd9af4488b66c/numpy-2.2.6-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:c820a93b0255bc360f53eca31a0e676fd1101f673dda8da93454a12e23fc5f7a", size = 14406743, upload-time = "2025-05-17T21:31:41.087Z" }, { url = "https://files.pythonhosted.org/packages/4a/9f/0121e375000b5e50ffdd8b25bf78d8e1a5aa4cca3f185d41265198c7b834/numpy-2.2.6-cp311-cp311-macosx_14_0_arm64.whl", hash = "sha256:3d70692235e759f260c3d837193090014aebdf026dfd167834bcba43e30c2a42", size = 5352616, upload-time = "2025-05-17T21:31:50.072Z" }, @@ -855,10 +721,6 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/76/95/bef5b37f29fc5e739947e9ce5179ad402875633308504a52d188302319c8/numpy-2.2.6-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:8e9ace4a37db23421249ed236fdcdd457d671e25146786dfc96835cd951aa7c1", size = 18385260, upload-time = "2025-05-17T21:43:05.189Z" }, { url = "https://files.pythonhosted.org/packages/09/04/f2f83279d287407cf36a7a8053a5abe7be3622a4363337338f2585e4afda/numpy-2.2.6-cp313-cp313t-win32.whl", hash = "sha256:038613e9fb8c72b0a41f025a7e4c3f0b7a1b5d768ece4796b674c8f3fe13efff", size = 6377225, upload-time = "2025-05-17T21:43:16.254Z" }, { url = "https://files.pythonhosted.org/packages/67/0e/35082d13c09c02c011cf21570543d202ad929d961c02a147493cb0c2bdf5/numpy-2.2.6-cp313-cp313t-win_amd64.whl", hash = "sha256:6031dd6dfecc0cf9f668681a37648373bddd6421fff6c66ec1624eed0180ee06", size = 12771374, upload-time = "2025-05-17T21:43:35.479Z" }, - { url = "https://files.pythonhosted.org/packages/9e/3b/d94a75f4dbf1ef5d321523ecac21ef23a3cd2ac8b78ae2aac40873590229/numpy-2.2.6-pp310-pypy310_pp73-macosx_10_15_x86_64.whl", hash = "sha256:0b605b275d7bd0c640cad4e5d30fa701a8d59302e127e5f79138ad62762c3e3d", size = 21040391, upload-time = "2025-05-17T21:44:35.948Z" }, - { url = "https://files.pythonhosted.org/packages/17/f4/09b2fa1b58f0fb4f7c7963a1649c64c4d315752240377ed74d9cd878f7b5/numpy-2.2.6-pp310-pypy310_pp73-macosx_14_0_x86_64.whl", hash = "sha256:7befc596a7dc9da8a337f79802ee8adb30a552a94f792b9c9d18c840055907db", size = 6786754, upload-time = "2025-05-17T21:44:47.446Z" }, - { url = "https://files.pythonhosted.org/packages/af/30/feba75f143bdc868a1cc3f44ccfa6c4b9ec522b36458e738cd00f67b573f/numpy-2.2.6-pp310-pypy310_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ce47521a4754c8f4593837384bd3424880629f718d87c5d44f8ed763edd63543", size = 16643476, upload-time = "2025-05-17T21:45:11.871Z" }, - { url = "https://files.pythonhosted.org/packages/37/48/ac2a9584402fb6c0cd5b5d1a91dcf176b15760130dd386bbafdbfe3640bf/numpy-2.2.6-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:d042d24c90c41b54fd506da306759e06e568864df8ec17ccc17e9e884634fd00", size = 12812666, upload-time = "2025-05-17T21:45:31.426Z" }, ] [[package]] @@ -896,13 +758,6 @@ dependencies = [ ] sdist = { url = "https://files.pythonhosted.org/packages/72/51/48f713c4c728d7c55ef7444ba5ea027c26998d96d1a40953b346438602fc/pandas-2.3.0.tar.gz", hash = "sha256:34600ab34ebf1131a7613a260a61dbe8b62c188ec0ea4c296da7c9a06b004133", size = 4484490, upload-time = "2025-06-05T03:27:54.133Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/e2/2d/df6b98c736ba51b8eaa71229e8fcd91233a831ec00ab520e1e23090cc072/pandas-2.3.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:625466edd01d43b75b1883a64d859168e4556261a5035b32f9d743b67ef44634", size = 11527531, upload-time = "2025-06-05T03:25:48.648Z" }, - { url = "https://files.pythonhosted.org/packages/77/1c/3f8c331d223f86ba1d0ed7d3ed7fcf1501c6f250882489cc820d2567ddbf/pandas-2.3.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:a6872d695c896f00df46b71648eea332279ef4077a409e2fe94220208b6bb675", size = 10774764, upload-time = "2025-06-05T03:25:53.228Z" }, - { url = "https://files.pythonhosted.org/packages/1b/45/d2599400fad7fe06b849bd40b52c65684bc88fbe5f0a474d0513d057a377/pandas-2.3.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f4dd97c19bd06bc557ad787a15b6489d2614ddaab5d104a0310eb314c724b2d2", size = 11711963, upload-time = "2025-06-05T03:25:56.855Z" }, - { url = "https://files.pythonhosted.org/packages/66/f8/5508bc45e994e698dbc93607ee6b9b6eb67df978dc10ee2b09df80103d9e/pandas-2.3.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:034abd6f3db8b9880aaee98f4f5d4dbec7c4829938463ec046517220b2f8574e", size = 12349446, upload-time = "2025-06-05T03:26:01.292Z" }, - { url = "https://files.pythonhosted.org/packages/f7/fc/17851e1b1ea0c8456ba90a2f514c35134dd56d981cf30ccdc501a0adeac4/pandas-2.3.0-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:23c2b2dc5213810208ca0b80b8666670eb4660bbfd9d45f58592cc4ddcfd62e1", size = 12920002, upload-time = "2025-06-06T00:00:07.925Z" }, - { url = "https://files.pythonhosted.org/packages/a1/9b/8743be105989c81fa33f8e2a4e9822ac0ad4aaf812c00fee6bb09fc814f9/pandas-2.3.0-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:39ff73ec07be5e90330cc6ff5705c651ace83374189dcdcb46e6ff54b4a72cd6", size = 13651218, upload-time = "2025-06-05T03:26:09.731Z" }, - { url = "https://files.pythonhosted.org/packages/26/fa/8eeb2353f6d40974a6a9fd4081ad1700e2386cf4264a8f28542fd10b3e38/pandas-2.3.0-cp310-cp310-win_amd64.whl", hash = "sha256:40cecc4ea5abd2921682b57532baea5588cc5f80f0231c624056b146887274d2", size = 11082485, upload-time = "2025-06-05T03:26:17.572Z" }, { url = "https://files.pythonhosted.org/packages/96/1e/ba313812a699fe37bf62e6194265a4621be11833f5fce46d9eae22acb5d7/pandas-2.3.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:8adff9f138fc614347ff33812046787f7d43b3cef7c0f0171b3340cae333f6ca", size = 11551836, upload-time = "2025-06-05T03:26:22.784Z" }, { url = "https://files.pythonhosted.org/packages/1b/cc/0af9c07f8d714ea563b12383a7e5bde9479cf32413ee2f346a9c5a801f22/pandas-2.3.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:e5f08eb9a445d07720776df6e641975665c9ea12c9d8a331e0f6890f2dcd76ef", size = 10807977, upload-time = "2025-06-05T16:50:11.109Z" }, { url = "https://files.pythonhosted.org/packages/ee/3e/8c0fb7e2cf4a55198466ced1ca6a9054ae3b7e7630df7757031df10001fd/pandas-2.3.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:fa35c266c8cd1a67d75971a1912b185b492d257092bdd2709bbdebe574ed228d", size = 11788230, upload-time = "2025-06-05T03:26:27.417Z" }, @@ -947,15 +802,6 @@ dependencies = [ ] sdist = { url = "https://files.pythonhosted.org/packages/23/7c/009c12b86c7cc6c403aec80f8a4308598dfc5995e5c523a5491faaa3952e/pendulum-3.1.0.tar.gz", hash = "sha256:66f96303560f41d097bee7d2dc98ffca716fbb3a832c4b3062034c2d45865015", size = 85930, upload-time = "2025-04-19T14:30:01.675Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/b4/d8/398cd27903a6899d0ae47b896d88e0b15849fc334931a6732e7ce3be9a45/pendulum-3.1.0-cp310-cp310-macosx_10_12_x86_64.whl", hash = "sha256:aa545a59e6517cf43597455a6fb44daa4a6e08473d67a7ad34e4fa951efb9620", size = 338637, upload-time = "2025-04-19T14:00:56.429Z" }, - { url = "https://files.pythonhosted.org/packages/aa/9d/a125554919c6db14e189393254c7781ee98ed5a121b6c05652d353b03c12/pendulum-3.1.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:299df2da6c490ede86bb8d58c65e33d7a2a42479d21475a54b467b03ccb88531", size = 326003, upload-time = "2025-04-19T14:00:58.192Z" }, - { url = "https://files.pythonhosted.org/packages/53/9f/43a5a902f904e06252c259c2f6cf2dceafbb25aef158df08f79c0089dfd7/pendulum-3.1.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:dbaa66e3ab179a2746eec67462f852a5d555bd709c25030aef38477468dd008e", size = 344335, upload-time = "2025-04-19T14:00:59.985Z" }, - { url = "https://files.pythonhosted.org/packages/ca/24/00fcd6abd1f7623d2bbcca048b45f01aa8bb6b647e0477c3a8ea6094335c/pendulum-3.1.0-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:c3907ab3744c32e339c358d88ec80cd35fa2d4b25c77a3c67e6b39e99b7090c5", size = 382169, upload-time = "2025-04-19T14:01:01.411Z" }, - { url = "https://files.pythonhosted.org/packages/32/bc/20a87f24c26c6c4daf3c69311208b28130b4d19c006da16efc0e55715963/pendulum-3.1.0-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:8244958c5bc4ed1c47ee84b098ddd95287a3fc59e569ca6e2b664c6396138ec4", size = 436675, upload-time = "2025-04-19T14:01:03.068Z" }, - { url = "https://files.pythonhosted.org/packages/1d/eb/3b1818a796408a250b8e6cfaa5372b991c0cbec768e02e0f9a226755383d/pendulum-3.1.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ca5722b3993b85ff7dfced48d86b318f863c359877b6badf1a3601e35199ef8f", size = 353728, upload-time = "2025-04-19T14:01:04.483Z" }, - { url = "https://files.pythonhosted.org/packages/36/23/755ef61f863b2777925171a59509540205b561a9e07ee7de0b5be9226bea/pendulum-3.1.0-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:5b77a3dc010eea1a4916ef3771163d808bfc3e02b894c37df311287f18e5b764", size = 524465, upload-time = "2025-04-19T14:01:05.865Z" }, - { url = "https://files.pythonhosted.org/packages/07/1f/a3e5f08890d13d93eee725778bfeaa233db5c55463e526857dffbc1a47e4/pendulum-3.1.0-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:2d6e1eff4a15fdb8fb3867c5469e691c2465eef002a6a541c47b48a390ff4cf4", size = 525690, upload-time = "2025-04-19T14:01:07.707Z" }, - { url = "https://files.pythonhosted.org/packages/43/c5/bf8ce472b81e8f5f074e8ba39899d288acce417c2c4a9ec7486d56970e28/pendulum-3.1.0-cp310-cp310-win_amd64.whl", hash = "sha256:73de43ec85b46ac75db848c8e2f3f5d086e90b11cd9c7f029e14c8d748d920e2", size = 260356, upload-time = "2025-04-19T14:01:09.339Z" }, { url = "https://files.pythonhosted.org/packages/5e/6e/d28d3c22e6708b819a94c05bd05a3dfaed5c685379e8b6dc4b34b473b942/pendulum-3.1.0-cp311-cp311-macosx_10_12_x86_64.whl", hash = "sha256:61a03d14f8c64d13b2f7d5859e4b4053c4a7d3b02339f6c71f3e4606bfd67423", size = 338596, upload-time = "2025-04-19T14:01:11.306Z" }, { url = "https://files.pythonhosted.org/packages/e1/e6/43324d58021d463c2eeb6146b169d2c935f2f840f9e45ac2d500453d954c/pendulum-3.1.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:e674ed2d158afa5c361e60f1f67872dc55b492a10cacdaa7fcd7b7da5f158f24", size = 325854, upload-time = "2025-04-19T14:01:13.156Z" }, { url = "https://files.pythonhosted.org/packages/b0/a7/d2ae79b960bfdea94dab67e2f118697b08bc9e98eb6bd8d32c4d99240da3/pendulum-3.1.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:7c75377eb16e58bbe7e03ea89eeea49be6fc5de0934a4aef0e263f8b4fa71bc2", size = 344334, upload-time = "2025-04-19T14:01:15.151Z" }, @@ -986,13 +832,6 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/01/33/2c0d5216cc53d16db0c4b3d510f141ee0a540937f8675948541190fbd48b/pendulum-3.1.0-cp313-cp313-musllinux_1_1_x86_64.whl", hash = "sha256:7378084fe54faab4ee481897a00b710876f2e901ded6221671e827a253e643f2", size = 523221, upload-time = "2025-04-19T14:01:53.275Z" }, { url = "https://files.pythonhosted.org/packages/51/89/8de955c339c31aeae77fd86d3225509b998c81875e9dba28cb88b8cbf4b3/pendulum-3.1.0-cp313-cp313-win_amd64.whl", hash = "sha256:8539db7ae2c8da430ac2515079e288948c8ebf7eb1edd3e8281b5cdf433040d6", size = 260501, upload-time = "2025-04-19T14:01:54.749Z" }, { url = "https://files.pythonhosted.org/packages/15/c3/226a3837363e94f8722461848feec18bfdd7d5172564d53aa3c3397ff01e/pendulum-3.1.0-cp313-cp313-win_arm64.whl", hash = "sha256:1ce26a608e1f7387cd393fba2a129507c4900958d4f47b90757ec17656856571", size = 253087, upload-time = "2025-04-19T14:01:55.998Z" }, - { url = "https://files.pythonhosted.org/packages/66/10/3258c084653606d2be2c7168998eda4a57cf1559cecb43cf1100000fda5f/pendulum-3.1.0-pp310-pypy310_pp73-macosx_10_12_x86_64.whl", hash = "sha256:d2cac744940299d8da41a3ed941aa1e02b5abbc9ae2c525f3aa2ae30c28a86b5", size = 339442, upload-time = "2025-04-19T14:02:12.512Z" }, - { url = "https://files.pythonhosted.org/packages/98/d5/98a1a10cd1cfb3390fbf070864e9a10de8e70a9d4509832132f4d900d655/pendulum-3.1.0-pp310-pypy310_pp73-macosx_11_0_arm64.whl", hash = "sha256:ffb39c3f3906a9c9a108fa98e5556f18b52d2c6451984bbfe2f14436ec4fc9d4", size = 326609, upload-time = "2025-04-19T14:02:13.838Z" }, - { url = "https://files.pythonhosted.org/packages/0a/2e/448abdebc11b9c54e190d273cb084162643199fc184cb1bb6bff7900e67f/pendulum-3.1.0-pp310-pypy310_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ebe18b1c2eb364064cc4a68a65900f1465cac47d0891dab82341766bcc05b40c", size = 344777, upload-time = "2025-04-19T14:02:15.512Z" }, - { url = "https://files.pythonhosted.org/packages/ed/91/ee857bbd51168bf08b89c3a4705c920725eee0f830ccc513b8370f6ce71d/pendulum-3.1.0-pp310-pypy310_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a9e9b28a35cec9fcd90f224b4878456129a057dbd694fc8266a9393834804995", size = 354404, upload-time = "2025-04-19T14:02:16.91Z" }, - { url = "https://files.pythonhosted.org/packages/bc/d4/e63a57df65e2b2d10f3aa917a4069be9abf5ac7d56d11336e0510742d8a6/pendulum-3.1.0-pp310-pypy310_pp73-musllinux_1_1_aarch64.whl", hash = "sha256:a3be19b73a9c6a866724419295482f817727e635ccc82f07ae6f818943a1ee96", size = 524948, upload-time = "2025-04-19T14:02:18.808Z" }, - { url = "https://files.pythonhosted.org/packages/93/87/04e74600c5a5674e5f341b8888b530a9de9b84b31889f80fac3bee3e9e87/pendulum-3.1.0-pp310-pypy310_pp73-musllinux_1_1_x86_64.whl", hash = "sha256:24a53b523819bda4c70245687a589b5ea88711f7caac4be5f276d843fe63076b", size = 526340, upload-time = "2025-04-19T14:02:20.242Z" }, - { url = "https://files.pythonhosted.org/packages/48/27/d3577a5f6f7d1fbf1138d87ce21ebab363c78642513b991d1c424d658d09/pendulum-3.1.0-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:bd701789414fbd0be3c75f46803f31e91140c23821e4bcb0fa2bddcdd051c425", size = 261089, upload-time = "2025-04-19T14:02:21.631Z" }, { url = "https://files.pythonhosted.org/packages/6e/23/e98758924d1b3aac11a626268eabf7f3cf177e7837c28d47bf84c64532d0/pendulum-3.1.0-py3-none-any.whl", hash = "sha256:f9178c2a8e291758ade1e8dd6371b1d26d08371b4c7730a6e9a3ef8b16ebae0f", size = 111799, upload-time = "2025-04-19T14:02:34.739Z" }, ] @@ -1002,17 +841,6 @@ version = "11.2.1" source = { registry = "https://pypi.org/simple" } sdist = { url = "https://files.pythonhosted.org/packages/af/cb/bb5c01fcd2a69335b86c22142b2bccfc3464087efb7fd382eee5ffc7fdf7/pillow-11.2.1.tar.gz", hash = "sha256:a64dd61998416367b7ef979b73d3a85853ba9bec4c2925f74e588879a58716b6", size = 47026707, upload-time = "2025-04-12T17:50:03.289Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/0d/8b/b158ad57ed44d3cc54db8d68ad7c0a58b8fc0e4c7a3f995f9d62d5b464a1/pillow-11.2.1-cp310-cp310-macosx_10_10_x86_64.whl", hash = "sha256:d57a75d53922fc20c165016a20d9c44f73305e67c351bbc60d1adaf662e74047", size = 3198442, upload-time = "2025-04-12T17:47:10.666Z" }, - { url = "https://files.pythonhosted.org/packages/b1/f8/bb5d956142f86c2d6cc36704943fa761f2d2e4c48b7436fd0a85c20f1713/pillow-11.2.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:127bf6ac4a5b58b3d32fc8289656f77f80567d65660bc46f72c0d77e6600cc95", size = 3030553, upload-time = "2025-04-12T17:47:13.153Z" }, - { url = "https://files.pythonhosted.org/packages/22/7f/0e413bb3e2aa797b9ca2c5c38cb2e2e45d88654e5b12da91ad446964cfae/pillow-11.2.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b4ba4be812c7a40280629e55ae0b14a0aafa150dd6451297562e1764808bbe61", size = 4405503, upload-time = "2025-04-12T17:47:15.36Z" }, - { url = "https://files.pythonhosted.org/packages/f3/b4/cc647f4d13f3eb837d3065824aa58b9bcf10821f029dc79955ee43f793bd/pillow-11.2.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c8bd62331e5032bc396a93609982a9ab6b411c05078a52f5fe3cc59234a3abd1", size = 4490648, upload-time = "2025-04-12T17:47:17.37Z" }, - { url = "https://files.pythonhosted.org/packages/c2/6f/240b772a3b35cdd7384166461567aa6713799b4e78d180c555bd284844ea/pillow-11.2.1-cp310-cp310-manylinux_2_28_aarch64.whl", hash = "sha256:562d11134c97a62fe3af29581f083033179f7ff435f78392565a1ad2d1c2c45c", size = 4508937, upload-time = "2025-04-12T17:47:19.066Z" }, - { url = "https://files.pythonhosted.org/packages/f3/5e/7ca9c815ade5fdca18853db86d812f2f188212792780208bdb37a0a6aef4/pillow-11.2.1-cp310-cp310-manylinux_2_28_x86_64.whl", hash = "sha256:c97209e85b5be259994eb5b69ff50c5d20cca0f458ef9abd835e262d9d88b39d", size = 4599802, upload-time = "2025-04-12T17:47:21.404Z" }, - { url = "https://files.pythonhosted.org/packages/02/81/c3d9d38ce0c4878a77245d4cf2c46d45a4ad0f93000227910a46caff52f3/pillow-11.2.1-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:0c3e6d0f59171dfa2e25d7116217543310908dfa2770aa64b8f87605f8cacc97", size = 4576717, upload-time = "2025-04-12T17:47:23.571Z" }, - { url = "https://files.pythonhosted.org/packages/42/49/52b719b89ac7da3185b8d29c94d0e6aec8140059e3d8adcaa46da3751180/pillow-11.2.1-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:cc1c3bc53befb6096b84165956e886b1729634a799e9d6329a0c512ab651e579", size = 4654874, upload-time = "2025-04-12T17:47:25.783Z" }, - { url = "https://files.pythonhosted.org/packages/5b/0b/ede75063ba6023798267023dc0d0401f13695d228194d2242d5a7ba2f964/pillow-11.2.1-cp310-cp310-win32.whl", hash = "sha256:312c77b7f07ab2139924d2639860e084ec2a13e72af54d4f08ac843a5fc9c79d", size = 2331717, upload-time = "2025-04-12T17:47:28.922Z" }, - { url = "https://files.pythonhosted.org/packages/ed/3c/9831da3edea527c2ed9a09f31a2c04e77cd705847f13b69ca60269eec370/pillow-11.2.1-cp310-cp310-win_amd64.whl", hash = "sha256:9bc7ae48b8057a611e5fe9f853baa88093b9a76303937449397899385da06fad", size = 2676204, upload-time = "2025-04-12T17:47:31.283Z" }, - { url = "https://files.pythonhosted.org/packages/01/97/1f66ff8a1503d8cbfc5bae4dc99d54c6ec1e22ad2b946241365320caabc2/pillow-11.2.1-cp310-cp310-win_arm64.whl", hash = "sha256:2728567e249cdd939f6cc3d1f049595c66e4187f3c34078cbc0a7d21c47482d2", size = 2414767, upload-time = "2025-04-12T17:47:34.655Z" }, { url = "https://files.pythonhosted.org/packages/68/08/3fbf4b98924c73037a8e8b4c2c774784805e0fb4ebca6c5bb60795c40125/pillow-11.2.1-cp311-cp311-macosx_10_10_x86_64.whl", hash = "sha256:35ca289f712ccfc699508c4658a1d14652e8033e9b69839edf83cbdd0ba39e70", size = 3198450, upload-time = "2025-04-12T17:47:37.135Z" }, { url = "https://files.pythonhosted.org/packages/84/92/6505b1af3d2849d5e714fc75ba9e69b7255c05ee42383a35a4d58f576b16/pillow-11.2.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:e0409af9f829f87a2dfb7e259f78f317a5351f2045158be321fd135973fff7bf", size = 3030550, upload-time = "2025-04-12T17:47:39.345Z" }, { url = "https://files.pythonhosted.org/packages/3c/8c/ac2f99d2a70ff966bc7eb13dacacfaab57c0549b2ffb351b6537c7840b12/pillow-11.2.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d4e5c5edee874dce4f653dbe59db7c73a600119fbea8d31f53423586ee2aafd7", size = 4415018, upload-time = "2025-04-12T17:47:41.128Z" }, @@ -1057,13 +885,6 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/b3/92/1ca0c3f09233bd7decf8f7105a1c4e3162fb9142128c74adad0fb361b7eb/pillow-11.2.1-cp313-cp313t-win32.whl", hash = "sha256:e0b55f27f584ed623221cfe995c912c61606be8513bfa0e07d2c674b4516d9dd", size = 2335774, upload-time = "2025-04-12T17:49:04.889Z" }, { url = "https://files.pythonhosted.org/packages/a5/ac/77525347cb43b83ae905ffe257bbe2cc6fd23acb9796639a1f56aa59d191/pillow-11.2.1-cp313-cp313t-win_amd64.whl", hash = "sha256:36d6b82164c39ce5482f649b437382c0fb2395eabc1e2b1702a6deb8ad647d6e", size = 2681895, upload-time = "2025-04-12T17:49:06.635Z" }, { url = "https://files.pythonhosted.org/packages/67/32/32dc030cfa91ca0fc52baebbba2e009bb001122a1daa8b6a79ad830b38d3/pillow-11.2.1-cp313-cp313t-win_arm64.whl", hash = "sha256:225c832a13326e34f212d2072982bb1adb210e0cc0b153e688743018c94a2681", size = 2417234, upload-time = "2025-04-12T17:49:08.399Z" }, - { url = "https://files.pythonhosted.org/packages/33/49/c8c21e4255b4f4a2c0c68ac18125d7f5460b109acc6dfdef1a24f9b960ef/pillow-11.2.1-pp310-pypy310_pp73-macosx_10_15_x86_64.whl", hash = "sha256:9b7b0d4fd2635f54ad82785d56bc0d94f147096493a79985d0ab57aedd563156", size = 3181727, upload-time = "2025-04-12T17:49:31.898Z" }, - { url = "https://files.pythonhosted.org/packages/6d/f1/f7255c0838f8c1ef6d55b625cfb286835c17e8136ce4351c5577d02c443b/pillow-11.2.1-pp310-pypy310_pp73-macosx_11_0_arm64.whl", hash = "sha256:aa442755e31c64037aa7c1cb186e0b369f8416c567381852c63444dd666fb772", size = 2999833, upload-time = "2025-04-12T17:49:34.2Z" }, - { url = "https://files.pythonhosted.org/packages/e2/57/9968114457bd131063da98d87790d080366218f64fa2943b65ac6739abb3/pillow-11.2.1-pp310-pypy310_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f0d3348c95b766f54b76116d53d4cb171b52992a1027e7ca50c81b43b9d9e363", size = 3437472, upload-time = "2025-04-12T17:49:36.294Z" }, - { url = "https://files.pythonhosted.org/packages/b2/1b/e35d8a158e21372ecc48aac9c453518cfe23907bb82f950d6e1c72811eb0/pillow-11.2.1-pp310-pypy310_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:85d27ea4c889342f7e35f6d56e7e1cb345632ad592e8c51b693d7b7556043ce0", size = 3459976, upload-time = "2025-04-12T17:49:38.988Z" }, - { url = "https://files.pythonhosted.org/packages/26/da/2c11d03b765efff0ccc473f1c4186dc2770110464f2177efaed9cf6fae01/pillow-11.2.1-pp310-pypy310_pp73-manylinux_2_28_aarch64.whl", hash = "sha256:bf2c33d6791c598142f00c9c4c7d47f6476731c31081331664eb26d6ab583e01", size = 3527133, upload-time = "2025-04-12T17:49:40.985Z" }, - { url = "https://files.pythonhosted.org/packages/79/1a/4e85bd7cadf78412c2a3069249a09c32ef3323650fd3005c97cca7aa21df/pillow-11.2.1-pp310-pypy310_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:e616e7154c37669fc1dfc14584f11e284e05d1c650e1c0f972f281c4ccc53193", size = 3571555, upload-time = "2025-04-12T17:49:42.964Z" }, - { url = "https://files.pythonhosted.org/packages/69/03/239939915216de1e95e0ce2334bf17a7870ae185eb390fab6d706aadbfc0/pillow-11.2.1-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:39ad2e0f424394e3aebc40168845fee52df1394a4673a6ee512d840d14ab3013", size = 2674713, upload-time = "2025-04-12T17:49:44.944Z" }, { url = "https://files.pythonhosted.org/packages/a4/ad/2613c04633c7257d9481ab21d6b5364b59fc5d75faafd7cb8693523945a3/pillow-11.2.1-pp311-pypy311_pp73-macosx_10_15_x86_64.whl", hash = "sha256:80f1df8dbe9572b4b7abdfa17eb5d78dd620b1d55d9e25f834efdbee872d3aed", size = 3181734, upload-time = "2025-04-12T17:49:46.789Z" }, { url = "https://files.pythonhosted.org/packages/a4/fd/dcdda4471ed667de57bb5405bb42d751e6cfdd4011a12c248b455c778e03/pillow-11.2.1-pp311-pypy311_pp73-macosx_11_0_arm64.whl", hash = "sha256:ea926cfbc3957090becbcbbb65ad177161a2ff2ad578b5a6ec9bb1e1cd78753c", size = 2999841, upload-time = "2025-04-12T17:49:48.812Z" }, { url = "https://files.pythonhosted.org/packages/ac/89/8a2536e95e77432833f0db6fd72a8d310c8e4272a04461fb833eb021bf94/pillow-11.2.1-pp311-pypy311_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:738db0e0941ca0376804d4de6a782c005245264edaa253ffce24e5a15cbdc7bd", size = 3437470, upload-time = "2025-04-12T17:49:50.831Z" }, @@ -1141,19 +962,6 @@ dependencies = [ ] sdist = { url = "https://files.pythonhosted.org/packages/ad/88/5f2260bdfae97aabf98f1778d43f69574390ad787afb646292a638c923d4/pydantic_core-2.33.2.tar.gz", hash = "sha256:7cb8bc3605c29176e1b105350d2e6474142d7c1bd1d9327c4a9bdb46bf827acc", size = 435195, upload-time = "2025-04-23T18:33:52.104Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/e5/92/b31726561b5dae176c2d2c2dc43a9c5bfba5d32f96f8b4c0a600dd492447/pydantic_core-2.33.2-cp310-cp310-macosx_10_12_x86_64.whl", hash = "sha256:2b3d326aaef0c0399d9afffeb6367d5e26ddc24d351dbc9c636840ac355dc5d8", size = 2028817, upload-time = "2025-04-23T18:30:43.919Z" }, - { url = "https://files.pythonhosted.org/packages/a3/44/3f0b95fafdaca04a483c4e685fe437c6891001bf3ce8b2fded82b9ea3aa1/pydantic_core-2.33.2-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:0e5b2671f05ba48b94cb90ce55d8bdcaaedb8ba00cc5359f6810fc918713983d", size = 1861357, upload-time = "2025-04-23T18:30:46.372Z" }, - { url = "https://files.pythonhosted.org/packages/30/97/e8f13b55766234caae05372826e8e4b3b96e7b248be3157f53237682e43c/pydantic_core-2.33.2-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0069c9acc3f3981b9ff4cdfaf088e98d83440a4c7ea1bc07460af3d4dc22e72d", size = 1898011, upload-time = "2025-04-23T18:30:47.591Z" }, - { url = "https://files.pythonhosted.org/packages/9b/a3/99c48cf7bafc991cc3ee66fd544c0aae8dc907b752f1dad2d79b1b5a471f/pydantic_core-2.33.2-cp310-cp310-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:d53b22f2032c42eaaf025f7c40c2e3b94568ae077a606f006d206a463bc69572", size = 1982730, upload-time = "2025-04-23T18:30:49.328Z" }, - { url = "https://files.pythonhosted.org/packages/de/8e/a5b882ec4307010a840fb8b58bd9bf65d1840c92eae7534c7441709bf54b/pydantic_core-2.33.2-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:0405262705a123b7ce9f0b92f123334d67b70fd1f20a9372b907ce1080c7ba02", size = 2136178, upload-time = "2025-04-23T18:30:50.907Z" }, - { url = "https://files.pythonhosted.org/packages/e4/bb/71e35fc3ed05af6834e890edb75968e2802fe98778971ab5cba20a162315/pydantic_core-2.33.2-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:4b25d91e288e2c4e0662b8038a28c6a07eaac3e196cfc4ff69de4ea3db992a1b", size = 2736462, upload-time = "2025-04-23T18:30:52.083Z" }, - { url = "https://files.pythonhosted.org/packages/31/0d/c8f7593e6bc7066289bbc366f2235701dcbebcd1ff0ef8e64f6f239fb47d/pydantic_core-2.33.2-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6bdfe4b3789761f3bcb4b1ddf33355a71079858958e3a552f16d5af19768fef2", size = 2005652, upload-time = "2025-04-23T18:30:53.389Z" }, - { url = "https://files.pythonhosted.org/packages/d2/7a/996d8bd75f3eda405e3dd219ff5ff0a283cd8e34add39d8ef9157e722867/pydantic_core-2.33.2-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:efec8db3266b76ef9607c2c4c419bdb06bf335ae433b80816089ea7585816f6a", size = 2113306, upload-time = "2025-04-23T18:30:54.661Z" }, - { url = "https://files.pythonhosted.org/packages/ff/84/daf2a6fb2db40ffda6578a7e8c5a6e9c8affb251a05c233ae37098118788/pydantic_core-2.33.2-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:031c57d67ca86902726e0fae2214ce6770bbe2f710dc33063187a68744a5ecac", size = 2073720, upload-time = "2025-04-23T18:30:56.11Z" }, - { url = "https://files.pythonhosted.org/packages/77/fb/2258da019f4825128445ae79456a5499c032b55849dbd5bed78c95ccf163/pydantic_core-2.33.2-cp310-cp310-musllinux_1_1_armv7l.whl", hash = "sha256:f8de619080e944347f5f20de29a975c2d815d9ddd8be9b9b7268e2e3ef68605a", size = 2244915, upload-time = "2025-04-23T18:30:57.501Z" }, - { url = "https://files.pythonhosted.org/packages/d8/7a/925ff73756031289468326e355b6fa8316960d0d65f8b5d6b3a3e7866de7/pydantic_core-2.33.2-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:73662edf539e72a9440129f231ed3757faab89630d291b784ca99237fb94db2b", size = 2241884, upload-time = "2025-04-23T18:30:58.867Z" }, - { url = "https://files.pythonhosted.org/packages/0b/b0/249ee6d2646f1cdadcb813805fe76265745c4010cf20a8eba7b0e639d9b2/pydantic_core-2.33.2-cp310-cp310-win32.whl", hash = "sha256:0a39979dcbb70998b0e505fb1556a1d550a0781463ce84ebf915ba293ccb7e22", size = 1910496, upload-time = "2025-04-23T18:31:00.078Z" }, - { url = "https://files.pythonhosted.org/packages/66/ff/172ba8f12a42d4b552917aa65d1f2328990d3ccfc01d5b7c943ec084299f/pydantic_core-2.33.2-cp310-cp310-win_amd64.whl", hash = "sha256:b0379a2b24882fef529ec3b4987cb5d003b9cda32256024e6fe1586ac45fc640", size = 1955019, upload-time = "2025-04-23T18:31:01.335Z" }, { url = "https://files.pythonhosted.org/packages/3f/8d/71db63483d518cbbf290261a1fc2839d17ff89fce7089e08cad07ccfce67/pydantic_core-2.33.2-cp311-cp311-macosx_10_12_x86_64.whl", hash = "sha256:4c5b0a576fb381edd6d27f0a85915c6daf2f8138dc5c267a57c08a62900758c7", size = 2028584, upload-time = "2025-04-23T18:31:03.106Z" }, { url = "https://files.pythonhosted.org/packages/24/2f/3cfa7244ae292dd850989f328722d2aef313f74ffc471184dc509e1e4e5a/pydantic_core-2.33.2-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:e799c050df38a639db758c617ec771fd8fb7a5f8eaaa4b27b101f266b216a246", size = 1855071, upload-time = "2025-04-23T18:31:04.621Z" }, { url = "https://files.pythonhosted.org/packages/b3/d3/4ae42d33f5e3f50dd467761304be2fa0a9417fbf09735bc2cce003480f2a/pydantic_core-2.33.2-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:dc46a01bf8d62f227d5ecee74178ffc448ff4e5197c756331f71efcc66dc980f", size = 1897823, upload-time = "2025-04-23T18:31:06.377Z" }, @@ -1199,15 +1007,6 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/a4/7d/e09391c2eebeab681df2b74bfe6c43422fffede8dc74187b2b0bf6fd7571/pydantic_core-2.33.2-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:61c18fba8e5e9db3ab908620af374db0ac1baa69f0f32df4f61ae23f15e586ac", size = 1806162, upload-time = "2025-04-23T18:32:20.188Z" }, { url = "https://files.pythonhosted.org/packages/f1/3d/847b6b1fed9f8ed3bb95a9ad04fbd0b212e832d4f0f50ff4d9ee5a9f15cf/pydantic_core-2.33.2-cp313-cp313t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:95237e53bb015f67b63c91af7518a62a8660376a6a0db19b89acc77a4d6199f5", size = 1981560, upload-time = "2025-04-23T18:32:22.354Z" }, { url = "https://files.pythonhosted.org/packages/6f/9a/e73262f6c6656262b5fdd723ad90f518f579b7bc8622e43a942eec53c938/pydantic_core-2.33.2-cp313-cp313t-win_amd64.whl", hash = "sha256:c2fc0a768ef76c15ab9238afa6da7f69895bb5d1ee83aeea2e3509af4472d0b9", size = 1935777, upload-time = "2025-04-23T18:32:25.088Z" }, - { url = "https://files.pythonhosted.org/packages/30/68/373d55e58b7e83ce371691f6eaa7175e3a24b956c44628eb25d7da007917/pydantic_core-2.33.2-pp310-pypy310_pp73-macosx_10_12_x86_64.whl", hash = "sha256:5c4aa4e82353f65e548c476b37e64189783aa5384903bfea4f41580f255fddfa", size = 2023982, upload-time = "2025-04-23T18:32:53.14Z" }, - { url = "https://files.pythonhosted.org/packages/a4/16/145f54ac08c96a63d8ed6442f9dec17b2773d19920b627b18d4f10a061ea/pydantic_core-2.33.2-pp310-pypy310_pp73-macosx_11_0_arm64.whl", hash = "sha256:d946c8bf0d5c24bf4fe333af284c59a19358aa3ec18cb3dc4370080da1e8ad29", size = 1858412, upload-time = "2025-04-23T18:32:55.52Z" }, - { url = "https://files.pythonhosted.org/packages/41/b1/c6dc6c3e2de4516c0bb2c46f6a373b91b5660312342a0cf5826e38ad82fa/pydantic_core-2.33.2-pp310-pypy310_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:87b31b6846e361ef83fedb187bb5b4372d0da3f7e28d85415efa92d6125d6e6d", size = 1892749, upload-time = "2025-04-23T18:32:57.546Z" }, - { url = "https://files.pythonhosted.org/packages/12/73/8cd57e20afba760b21b742106f9dbdfa6697f1570b189c7457a1af4cd8a0/pydantic_core-2.33.2-pp310-pypy310_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:aa9d91b338f2df0508606f7009fde642391425189bba6d8c653afd80fd6bb64e", size = 2067527, upload-time = "2025-04-23T18:32:59.771Z" }, - { url = "https://files.pythonhosted.org/packages/e3/d5/0bb5d988cc019b3cba4a78f2d4b3854427fc47ee8ec8e9eaabf787da239c/pydantic_core-2.33.2-pp310-pypy310_pp73-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:2058a32994f1fde4ca0480ab9d1e75a0e8c87c22b53a3ae66554f9af78f2fe8c", size = 2108225, upload-time = "2025-04-23T18:33:04.51Z" }, - { url = "https://files.pythonhosted.org/packages/f1/c5/00c02d1571913d496aabf146106ad8239dc132485ee22efe08085084ff7c/pydantic_core-2.33.2-pp310-pypy310_pp73-musllinux_1_1_aarch64.whl", hash = "sha256:0e03262ab796d986f978f79c943fc5f620381be7287148b8010b4097f79a39ec", size = 2069490, upload-time = "2025-04-23T18:33:06.391Z" }, - { url = "https://files.pythonhosted.org/packages/22/a8/dccc38768274d3ed3a59b5d06f59ccb845778687652daa71df0cab4040d7/pydantic_core-2.33.2-pp310-pypy310_pp73-musllinux_1_1_armv7l.whl", hash = "sha256:1a8695a8d00c73e50bff9dfda4d540b7dee29ff9b8053e38380426a85ef10052", size = 2237525, upload-time = "2025-04-23T18:33:08.44Z" }, - { url = "https://files.pythonhosted.org/packages/d4/e7/4f98c0b125dda7cf7ccd14ba936218397b44f50a56dd8c16a3091df116c3/pydantic_core-2.33.2-pp310-pypy310_pp73-musllinux_1_1_x86_64.whl", hash = "sha256:fa754d1850735a0b0e03bcffd9d4b4343eb417e47196e4485d9cca326073a42c", size = 2238446, upload-time = "2025-04-23T18:33:10.313Z" }, - { url = "https://files.pythonhosted.org/packages/ce/91/2ec36480fdb0b783cd9ef6795753c1dea13882f2e68e73bce76ae8c21e6a/pydantic_core-2.33.2-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:a11c8d26a50bfab49002947d3d237abe4d9e4b5bdc8846a63537b6488e197808", size = 2066678, upload-time = "2025-04-23T18:33:12.224Z" }, { url = "https://files.pythonhosted.org/packages/7b/27/d4ae6487d73948d6f20dddcd94be4ea43e74349b56eba82e9bdee2d7494c/pydantic_core-2.33.2-pp311-pypy311_pp73-macosx_10_12_x86_64.whl", hash = "sha256:dd14041875d09cc0f9308e37a6f8b65f5585cf2598a53aa0123df8b129d481f8", size = 2025200, upload-time = "2025-04-23T18:33:14.199Z" }, { url = "https://files.pythonhosted.org/packages/f1/b8/b3cb95375f05d33801024079b9392a5ab45267a63400bf1866e7ce0f0de4/pydantic_core-2.33.2-pp311-pypy311_pp73-macosx_11_0_arm64.whl", hash = "sha256:d87c561733f66531dced0da6e864f44ebf89a8fba55f31407b00c2f7f9449593", size = 1859123, upload-time = "2025-04-23T18:33:16.555Z" }, { url = "https://files.pythonhosted.org/packages/05/bc/0d0b5adeda59a261cd30a1235a445bf55c7e46ae44aea28f7bd6ed46e091/pydantic_core-2.33.2-pp311-pypy311_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:2f82865531efd18d6e07a04a17331af02cb7a651583c418df8266f17a63c6612", size = 1892852, upload-time = "2025-04-23T18:33:18.513Z" }, @@ -1238,11 +1037,8 @@ dependencies = [ { name = "numpy" }, { name = "optics-functions" }, { name = "pandas" }, - { name = "pendulum" }, { name = "pydantic" }, - { name = "rich" }, - { name = "scipy", version = "1.15.3", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version < '3.11'" }, - { name = "scipy", version = "1.16.0", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.11'" }, + { name = "scipy" }, { name = "tfs-pandas" }, ] @@ -1252,21 +1048,21 @@ all = [ { name = "flaky" }, { name = "joblib" }, { name = "numba" }, + { name = "pendulum" }, { name = "pytest" }, { name = "pytest-cov" }, { name = "pytest-mpl" }, { name = "pytest-randomly" }, { name = "pytest-xdist" }, + { name = "rich" }, { name = "ruff" }, - { name = "sphinx", version = "8.1.3", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version < '3.11'" }, - { name = "sphinx", version = "8.2.3", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.11'" }, + { name = "sphinx" }, { name = "sphinx-codeautolink" }, { name = "sphinx-copybutton" }, { name = "sphinx-design" }, { name = "sphinx-gallery" }, { name = "sphinx-issues" }, - { name = "sphinx-prompt", version = "1.9.0", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version < '3.11'" }, - { name = "sphinx-prompt", version = "1.10.0", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.11'" }, + { name = "sphinx-prompt" }, { name = "sphinx-rtd-theme" }, { name = "sphinxcontrib-bibtex" }, ] @@ -1275,27 +1071,31 @@ dev = [ ] docs = [ { name = "joblib" }, - { name = "sphinx", version = "8.1.3", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version < '3.11'" }, - { name = "sphinx", version = "8.2.3", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.11'" }, + { name = "sphinx" }, { name = "sphinx-codeautolink" }, { name = "sphinx-copybutton" }, { name = "sphinx-design" }, { name = "sphinx-gallery" }, { name = "sphinx-issues" }, - { name = "sphinx-prompt", version = "1.9.0", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version < '3.11'" }, - { name = "sphinx-prompt", version = "1.10.0", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.11'" }, + { name = "sphinx-prompt" }, { name = "sphinx-rtd-theme" }, { name = "sphinxcontrib-bibtex" }, ] +monitor = [ + { name = "pendulum" }, + { name = "rich" }, +] test = [ { name = "coverage", extra = ["toml"] }, { name = "flaky" }, { name = "numba" }, + { name = "pendulum" }, { name = "pytest" }, { name = "pytest-cov" }, { name = "pytest-mpl" }, { name = "pytest-randomly" }, { name = "pytest-xdist" }, + { name = "rich" }, ] [package.metadata] @@ -1314,7 +1114,9 @@ requires-dist = [ { name = "numpy", specifier = ">=2.0" }, { name = "optics-functions", specifier = ">=0.1" }, { name = "pandas", specifier = ">=2.0" }, - { name = "pendulum", specifier = ">=3.0" }, + { name = "pendulum", marker = "extra == 'all'", specifier = ">=3.0" }, + { name = "pendulum", marker = "extra == 'monitor'", specifier = ">=3.0" }, + { name = "pendulum", marker = "extra == 'test'", specifier = ">=3.0" }, { name = "pydantic", specifier = ">=2.0" }, { name = "pytest", marker = "extra == 'all'", specifier = ">=8.0" }, { name = "pytest", marker = "extra == 'test'", specifier = ">=8.0" }, @@ -1326,7 +1128,9 @@ requires-dist = [ { name = "pytest-randomly", marker = "extra == 'test'", specifier = ">=3.10" }, { name = "pytest-xdist", marker = "extra == 'all'", specifier = ">=3.0" }, { name = "pytest-xdist", marker = "extra == 'test'", specifier = ">=3.0" }, - { name = "rich", specifier = ">=13.0" }, + { name = "rich", marker = "extra == 'all'", specifier = ">=13.0" }, + { name = "rich", marker = "extra == 'monitor'", specifier = ">=13.0" }, + { name = "rich", marker = "extra == 'test'", specifier = ">=13.0" }, { name = "ruff", marker = "extra == 'all'", specifier = ">=0.12" }, { name = "ruff", marker = "extra == 'dev'", specifier = ">=0.12" }, { name = "scipy", specifier = ">=1.10" }, @@ -1350,7 +1154,7 @@ requires-dist = [ { name = "sphinxcontrib-bibtex", marker = "extra == 'docs'", specifier = ">=2.4" }, { name = "tfs-pandas", specifier = ">=3.8" }, ] -provides-extras = ["all", "dev", "docs", "test"] +provides-extras = ["all", "dev", "docs", "monitor", "test"] [[package]] name = "pyparsing" @@ -1367,12 +1171,10 @@ version = "8.4.1" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "colorama", marker = "sys_platform == 'win32'" }, - { name = "exceptiongroup", marker = "python_full_version < '3.11'" }, { name = "iniconfig" }, { name = "packaging" }, { name = "pluggy" }, { name = "pygments" }, - { name = "tomli", marker = "python_full_version < '3.11'" }, ] sdist = { url = "https://files.pythonhosted.org/packages/08/ba/45911d754e8eba3d5a841a5ce61a65a685ff1798421ac054f85aa8747dfb/pytest-8.4.1.tar.gz", hash = "sha256:7c67fd69174877359ed9371ec3af8a3d2b04741818c51e5e99cc1742251fa93c", size = 1517714, upload-time = "2025-06-18T05:48:06.109Z" } wheels = [ @@ -1461,15 +1263,6 @@ version = "6.0.2" source = { registry = "https://pypi.org/simple" } sdist = { url = "https://files.pythonhosted.org/packages/54/ed/79a089b6be93607fa5cdaedf301d7dfb23af5f25c398d5ead2525b063e17/pyyaml-6.0.2.tar.gz", hash = "sha256:d584d9ec91ad65861cc08d42e834324ef890a082e591037abe114850ff7bbc3e", size = 130631, upload-time = "2024-08-06T20:33:50.674Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/9b/95/a3fac87cb7158e231b5a6012e438c647e1a87f09f8e0d123acec8ab8bf71/PyYAML-6.0.2-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:0a9a2848a5b7feac301353437eb7d5957887edbf81d56e903999a75a3d743086", size = 184199, upload-time = "2024-08-06T20:31:40.178Z" }, - { url = "https://files.pythonhosted.org/packages/c7/7a/68bd47624dab8fd4afbfd3c48e3b79efe09098ae941de5b58abcbadff5cb/PyYAML-6.0.2-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:29717114e51c84ddfba879543fb232a6ed60086602313ca38cce623c1d62cfbf", size = 171758, upload-time = "2024-08-06T20:31:42.173Z" }, - { url = "https://files.pythonhosted.org/packages/49/ee/14c54df452143b9ee9f0f29074d7ca5516a36edb0b4cc40c3f280131656f/PyYAML-6.0.2-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:8824b5a04a04a047e72eea5cec3bc266db09e35de6bdfe34c9436ac5ee27d237", size = 718463, upload-time = "2024-08-06T20:31:44.263Z" }, - { url = "https://files.pythonhosted.org/packages/4d/61/de363a97476e766574650d742205be468921a7b532aa2499fcd886b62530/PyYAML-6.0.2-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:7c36280e6fb8385e520936c3cb3b8042851904eba0e58d277dca80a5cfed590b", size = 719280, upload-time = "2024-08-06T20:31:50.199Z" }, - { url = "https://files.pythonhosted.org/packages/6b/4e/1523cb902fd98355e2e9ea5e5eb237cbc5f3ad5f3075fa65087aa0ecb669/PyYAML-6.0.2-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ec031d5d2feb36d1d1a24380e4db6d43695f3748343d99434e6f5f9156aaa2ed", size = 751239, upload-time = "2024-08-06T20:31:52.292Z" }, - { url = "https://files.pythonhosted.org/packages/b7/33/5504b3a9a4464893c32f118a9cc045190a91637b119a9c881da1cf6b7a72/PyYAML-6.0.2-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:936d68689298c36b53b29f23c6dbb74de12b4ac12ca6cfe0e047bedceea56180", size = 695802, upload-time = "2024-08-06T20:31:53.836Z" }, - { url = "https://files.pythonhosted.org/packages/5c/20/8347dcabd41ef3a3cdc4f7b7a2aff3d06598c8779faa189cdbf878b626a4/PyYAML-6.0.2-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:23502f431948090f597378482b4812b0caae32c22213aecf3b55325e049a6c68", size = 720527, upload-time = "2024-08-06T20:31:55.565Z" }, - { url = "https://files.pythonhosted.org/packages/be/aa/5afe99233fb360d0ff37377145a949ae258aaab831bde4792b32650a4378/PyYAML-6.0.2-cp310-cp310-win32.whl", hash = "sha256:2e99c6826ffa974fe6e27cdb5ed0021786b03fc98e5ee3c5bfe1fd5015f42b99", size = 144052, upload-time = "2024-08-06T20:31:56.914Z" }, - { url = "https://files.pythonhosted.org/packages/b5/84/0fa4b06f6d6c958d207620fc60005e241ecedceee58931bb20138e1e5776/PyYAML-6.0.2-cp310-cp310-win_amd64.whl", hash = "sha256:a4d3091415f010369ae4ed1fc6b79def9416358877534caf6a0fdd2146c87a3e", size = 161774, upload-time = "2024-08-06T20:31:58.304Z" }, { url = "https://files.pythonhosted.org/packages/f8/aa/7af4e81f7acba21a4c6be026da38fd2b872ca46226673c89a758ebdc4fd2/PyYAML-6.0.2-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:cc1c1159b3d456576af7a3e4d1ba7e6924cb39de8f67111c735f6fc832082774", size = 184612, upload-time = "2024-08-06T20:32:03.408Z" }, { url = "https://files.pythonhosted.org/packages/8b/62/b9faa998fd185f65c1371643678e4d58254add437edb764a08c5a98fb986/PyYAML-6.0.2-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:1e2120ef853f59c7419231f3bf4e7021f1b936f6ebd222406c3b60212205d2ee", size = 172040, upload-time = "2024-08-06T20:32:04.926Z" }, { url = "https://files.pythonhosted.org/packages/ad/0c/c804f5f922a9a6563bab712d8dcc70251e8af811fce4524d57c2c0fd49a4/PyYAML-6.0.2-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5d225db5a45f21e78dd9358e58a98702a0302f2659a3c6cd320564b75b86f47c", size = 736829, upload-time = "2024-08-06T20:32:06.459Z" }, @@ -1521,7 +1314,6 @@ source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "markdown-it-py" }, { name = "pygments" }, - { name = "typing-extensions", marker = "python_full_version < '3.11'" }, ] sdist = { url = "https://files.pythonhosted.org/packages/a1/53/830aa4c3066a8ab0ae9a9955976fb770fe9c6102117c8ec4ab3ea62d89e8/rich-14.0.0.tar.gz", hash = "sha256:82f1bc23a6a21ebca4ae0c45af9bdbc492ed20231dcb63f297d6d1021a9d5725", size = 224078, upload-time = "2025-03-30T14:15:14.23Z" } wheels = [ @@ -1562,75 +1354,12 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/d0/33/4d3e79e4a84533d6cd526bfb42c020a23256ae5e4265d858bd1287831f7d/ruff-0.12.0-py3-none-win_arm64.whl", hash = "sha256:8cd24580405ad8c1cc64d61725bca091d6b6da7eb3d36f72cc605467069d7e8b", size = 10724946, upload-time = "2025-06-17T15:19:23.952Z" }, ] -[[package]] -name = "scipy" -version = "1.15.3" -source = { registry = "https://pypi.org/simple" } -resolution-markers = [ - "python_full_version < '3.11'", -] -dependencies = [ - { name = "numpy", marker = "python_full_version < '3.11'" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/0f/37/6964b830433e654ec7485e45a00fc9a27cf868d622838f6b6d9c5ec0d532/scipy-1.15.3.tar.gz", hash = "sha256:eae3cf522bc7df64b42cad3925c876e1b0b6c35c1337c93e12c0f366f55b0eaf", size = 59419214, upload-time = "2025-05-08T16:13:05.955Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/78/2f/4966032c5f8cc7e6a60f1b2e0ad686293b9474b65246b0c642e3ef3badd0/scipy-1.15.3-cp310-cp310-macosx_10_13_x86_64.whl", hash = "sha256:a345928c86d535060c9c2b25e71e87c39ab2f22fc96e9636bd74d1dbf9de448c", size = 38702770, upload-time = "2025-05-08T16:04:20.849Z" }, - { url = "https://files.pythonhosted.org/packages/a0/6e/0c3bf90fae0e910c274db43304ebe25a6b391327f3f10b5dcc638c090795/scipy-1.15.3-cp310-cp310-macosx_12_0_arm64.whl", hash = "sha256:ad3432cb0f9ed87477a8d97f03b763fd1d57709f1bbde3c9369b1dff5503b253", size = 30094511, upload-time = "2025-05-08T16:04:27.103Z" }, - { url = "https://files.pythonhosted.org/packages/ea/b1/4deb37252311c1acff7f101f6453f0440794f51b6eacb1aad4459a134081/scipy-1.15.3-cp310-cp310-macosx_14_0_arm64.whl", hash = "sha256:aef683a9ae6eb00728a542b796f52a5477b78252edede72b8327a886ab63293f", size = 22368151, upload-time = "2025-05-08T16:04:31.731Z" }, - { url = "https://files.pythonhosted.org/packages/38/7d/f457626e3cd3c29b3a49ca115a304cebb8cc6f31b04678f03b216899d3c6/scipy-1.15.3-cp310-cp310-macosx_14_0_x86_64.whl", hash = "sha256:1c832e1bd78dea67d5c16f786681b28dd695a8cb1fb90af2e27580d3d0967e92", size = 25121732, upload-time = "2025-05-08T16:04:36.596Z" }, - { url = "https://files.pythonhosted.org/packages/db/0a/92b1de4a7adc7a15dcf5bddc6e191f6f29ee663b30511ce20467ef9b82e4/scipy-1.15.3-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:263961f658ce2165bbd7b99fa5135195c3a12d9bef045345016b8b50c315cb82", size = 35547617, upload-time = "2025-05-08T16:04:43.546Z" }, - { url = "https://files.pythonhosted.org/packages/8e/6d/41991e503e51fc1134502694c5fa7a1671501a17ffa12716a4a9151af3df/scipy-1.15.3-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9e2abc762b0811e09a0d3258abee2d98e0c703eee49464ce0069590846f31d40", size = 37662964, upload-time = "2025-05-08T16:04:49.431Z" }, - { url = "https://files.pythonhosted.org/packages/25/e1/3df8f83cb15f3500478c889be8fb18700813b95e9e087328230b98d547ff/scipy-1.15.3-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:ed7284b21a7a0c8f1b6e5977ac05396c0d008b89e05498c8b7e8f4a1423bba0e", size = 37238749, upload-time = "2025-05-08T16:04:55.215Z" }, - { url = "https://files.pythonhosted.org/packages/93/3e/b3257cf446f2a3533ed7809757039016b74cd6f38271de91682aa844cfc5/scipy-1.15.3-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:5380741e53df2c566f4d234b100a484b420af85deb39ea35a1cc1be84ff53a5c", size = 40022383, upload-time = "2025-05-08T16:05:01.914Z" }, - { url = "https://files.pythonhosted.org/packages/d1/84/55bc4881973d3f79b479a5a2e2df61c8c9a04fcb986a213ac9c02cfb659b/scipy-1.15.3-cp310-cp310-win_amd64.whl", hash = "sha256:9d61e97b186a57350f6d6fd72640f9e99d5a4a2b8fbf4b9ee9a841eab327dc13", size = 41259201, upload-time = "2025-05-08T16:05:08.166Z" }, - { url = "https://files.pythonhosted.org/packages/96/ab/5cc9f80f28f6a7dff646c5756e559823614a42b1939d86dd0ed550470210/scipy-1.15.3-cp311-cp311-macosx_10_13_x86_64.whl", hash = "sha256:993439ce220d25e3696d1b23b233dd010169b62f6456488567e830654ee37a6b", size = 38714255, upload-time = "2025-05-08T16:05:14.596Z" }, - { url = "https://files.pythonhosted.org/packages/4a/4a/66ba30abe5ad1a3ad15bfb0b59d22174012e8056ff448cb1644deccbfed2/scipy-1.15.3-cp311-cp311-macosx_12_0_arm64.whl", hash = "sha256:34716e281f181a02341ddeaad584205bd2fd3c242063bd3423d61ac259ca7eba", size = 30111035, upload-time = "2025-05-08T16:05:20.152Z" }, - { url = "https://files.pythonhosted.org/packages/4b/fa/a7e5b95afd80d24313307f03624acc65801846fa75599034f8ceb9e2cbf6/scipy-1.15.3-cp311-cp311-macosx_14_0_arm64.whl", hash = "sha256:3b0334816afb8b91dab859281b1b9786934392aa3d527cd847e41bb6f45bee65", size = 22384499, upload-time = "2025-05-08T16:05:24.494Z" }, - { url = "https://files.pythonhosted.org/packages/17/99/f3aaddccf3588bb4aea70ba35328c204cadd89517a1612ecfda5b2dd9d7a/scipy-1.15.3-cp311-cp311-macosx_14_0_x86_64.whl", hash = "sha256:6db907c7368e3092e24919b5e31c76998b0ce1684d51a90943cb0ed1b4ffd6c1", size = 25152602, upload-time = "2025-05-08T16:05:29.313Z" }, - { url = "https://files.pythonhosted.org/packages/56/c5/1032cdb565f146109212153339f9cb8b993701e9fe56b1c97699eee12586/scipy-1.15.3-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:721d6b4ef5dc82ca8968c25b111e307083d7ca9091bc38163fb89243e85e3889", size = 35503415, upload-time = "2025-05-08T16:05:34.699Z" }, - { url = "https://files.pythonhosted.org/packages/bd/37/89f19c8c05505d0601ed5650156e50eb881ae3918786c8fd7262b4ee66d3/scipy-1.15.3-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:39cb9c62e471b1bb3750066ecc3a3f3052b37751c7c3dfd0fd7e48900ed52982", size = 37652622, upload-time = "2025-05-08T16:05:40.762Z" }, - { url = "https://files.pythonhosted.org/packages/7e/31/be59513aa9695519b18e1851bb9e487de66f2d31f835201f1b42f5d4d475/scipy-1.15.3-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:795c46999bae845966368a3c013e0e00947932d68e235702b5c3f6ea799aa8c9", size = 37244796, upload-time = "2025-05-08T16:05:48.119Z" }, - { url = "https://files.pythonhosted.org/packages/10/c0/4f5f3eeccc235632aab79b27a74a9130c6c35df358129f7ac8b29f562ac7/scipy-1.15.3-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:18aaacb735ab38b38db42cb01f6b92a2d0d4b6aabefeb07f02849e47f8fb3594", size = 40047684, upload-time = "2025-05-08T16:05:54.22Z" }, - { url = "https://files.pythonhosted.org/packages/ab/a7/0ddaf514ce8a8714f6ed243a2b391b41dbb65251affe21ee3077ec45ea9a/scipy-1.15.3-cp311-cp311-win_amd64.whl", hash = "sha256:ae48a786a28412d744c62fd7816a4118ef97e5be0bee968ce8f0a2fba7acf3bb", size = 41246504, upload-time = "2025-05-08T16:06:00.437Z" }, - { url = "https://files.pythonhosted.org/packages/37/4b/683aa044c4162e10ed7a7ea30527f2cbd92e6999c10a8ed8edb253836e9c/scipy-1.15.3-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:6ac6310fdbfb7aa6612408bd2f07295bcbd3fda00d2d702178434751fe48e019", size = 38766735, upload-time = "2025-05-08T16:06:06.471Z" }, - { url = "https://files.pythonhosted.org/packages/7b/7e/f30be3d03de07f25dc0ec926d1681fed5c732d759ac8f51079708c79e680/scipy-1.15.3-cp312-cp312-macosx_12_0_arm64.whl", hash = "sha256:185cd3d6d05ca4b44a8f1595af87f9c372bb6acf9c808e99aa3e9aa03bd98cf6", size = 30173284, upload-time = "2025-05-08T16:06:11.686Z" }, - { url = "https://files.pythonhosted.org/packages/07/9c/0ddb0d0abdabe0d181c1793db51f02cd59e4901da6f9f7848e1f96759f0d/scipy-1.15.3-cp312-cp312-macosx_14_0_arm64.whl", hash = "sha256:05dc6abcd105e1a29f95eada46d4a3f251743cfd7d3ae8ddb4088047f24ea477", size = 22446958, upload-time = "2025-05-08T16:06:15.97Z" }, - { url = "https://files.pythonhosted.org/packages/af/43/0bce905a965f36c58ff80d8bea33f1f9351b05fad4beaad4eae34699b7a1/scipy-1.15.3-cp312-cp312-macosx_14_0_x86_64.whl", hash = "sha256:06efcba926324df1696931a57a176c80848ccd67ce6ad020c810736bfd58eb1c", size = 25242454, upload-time = "2025-05-08T16:06:20.394Z" }, - { url = "https://files.pythonhosted.org/packages/56/30/a6f08f84ee5b7b28b4c597aca4cbe545535c39fe911845a96414700b64ba/scipy-1.15.3-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c05045d8b9bfd807ee1b9f38761993297b10b245f012b11b13b91ba8945f7e45", size = 35210199, upload-time = "2025-05-08T16:06:26.159Z" }, - { url = "https://files.pythonhosted.org/packages/0b/1f/03f52c282437a168ee2c7c14a1a0d0781a9a4a8962d84ac05c06b4c5b555/scipy-1.15.3-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:271e3713e645149ea5ea3e97b57fdab61ce61333f97cfae392c28ba786f9bb49", size = 37309455, upload-time = "2025-05-08T16:06:32.778Z" }, - { url = "https://files.pythonhosted.org/packages/89/b1/fbb53137f42c4bf630b1ffdfc2151a62d1d1b903b249f030d2b1c0280af8/scipy-1.15.3-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:6cfd56fc1a8e53f6e89ba3a7a7251f7396412d655bca2aa5611c8ec9a6784a1e", size = 36885140, upload-time = "2025-05-08T16:06:39.249Z" }, - { url = "https://files.pythonhosted.org/packages/2e/2e/025e39e339f5090df1ff266d021892694dbb7e63568edcfe43f892fa381d/scipy-1.15.3-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:0ff17c0bb1cb32952c09217d8d1eed9b53d1463e5f1dd6052c7857f83127d539", size = 39710549, upload-time = "2025-05-08T16:06:45.729Z" }, - { url = "https://files.pythonhosted.org/packages/e6/eb/3bf6ea8ab7f1503dca3a10df2e4b9c3f6b3316df07f6c0ded94b281c7101/scipy-1.15.3-cp312-cp312-win_amd64.whl", hash = "sha256:52092bc0472cfd17df49ff17e70624345efece4e1a12b23783a1ac59a1b728ed", size = 40966184, upload-time = "2025-05-08T16:06:52.623Z" }, - { url = "https://files.pythonhosted.org/packages/73/18/ec27848c9baae6e0d6573eda6e01a602e5649ee72c27c3a8aad673ebecfd/scipy-1.15.3-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:2c620736bcc334782e24d173c0fdbb7590a0a436d2fdf39310a8902505008759", size = 38728256, upload-time = "2025-05-08T16:06:58.696Z" }, - { url = "https://files.pythonhosted.org/packages/74/cd/1aef2184948728b4b6e21267d53b3339762c285a46a274ebb7863c9e4742/scipy-1.15.3-cp313-cp313-macosx_12_0_arm64.whl", hash = "sha256:7e11270a000969409d37ed399585ee530b9ef6aa99d50c019de4cb01e8e54e62", size = 30109540, upload-time = "2025-05-08T16:07:04.209Z" }, - { url = "https://files.pythonhosted.org/packages/5b/d8/59e452c0a255ec352bd0a833537a3bc1bfb679944c4938ab375b0a6b3a3e/scipy-1.15.3-cp313-cp313-macosx_14_0_arm64.whl", hash = "sha256:8c9ed3ba2c8a2ce098163a9bdb26f891746d02136995df25227a20e71c396ebb", size = 22383115, upload-time = "2025-05-08T16:07:08.998Z" }, - { url = "https://files.pythonhosted.org/packages/08/f5/456f56bbbfccf696263b47095291040655e3cbaf05d063bdc7c7517f32ac/scipy-1.15.3-cp313-cp313-macosx_14_0_x86_64.whl", hash = "sha256:0bdd905264c0c9cfa74a4772cdb2070171790381a5c4d312c973382fc6eaf730", size = 25163884, upload-time = "2025-05-08T16:07:14.091Z" }, - { url = "https://files.pythonhosted.org/packages/a2/66/a9618b6a435a0f0c0b8a6d0a2efb32d4ec5a85f023c2b79d39512040355b/scipy-1.15.3-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:79167bba085c31f38603e11a267d862957cbb3ce018d8b38f79ac043bc92d825", size = 35174018, upload-time = "2025-05-08T16:07:19.427Z" }, - { url = "https://files.pythonhosted.org/packages/b5/09/c5b6734a50ad4882432b6bb7c02baf757f5b2f256041da5df242e2d7e6b6/scipy-1.15.3-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c9deabd6d547aee2c9a81dee6cc96c6d7e9a9b1953f74850c179f91fdc729cb7", size = 37269716, upload-time = "2025-05-08T16:07:25.712Z" }, - { url = "https://files.pythonhosted.org/packages/77/0a/eac00ff741f23bcabd352731ed9b8995a0a60ef57f5fd788d611d43d69a1/scipy-1.15.3-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:dde4fc32993071ac0c7dd2d82569e544f0bdaff66269cb475e0f369adad13f11", size = 36872342, upload-time = "2025-05-08T16:07:31.468Z" }, - { url = "https://files.pythonhosted.org/packages/fe/54/4379be86dd74b6ad81551689107360d9a3e18f24d20767a2d5b9253a3f0a/scipy-1.15.3-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:f77f853d584e72e874d87357ad70f44b437331507d1c311457bed8ed2b956126", size = 39670869, upload-time = "2025-05-08T16:07:38.002Z" }, - { url = "https://files.pythonhosted.org/packages/87/2e/892ad2862ba54f084ffe8cc4a22667eaf9c2bcec6d2bff1d15713c6c0703/scipy-1.15.3-cp313-cp313-win_amd64.whl", hash = "sha256:b90ab29d0c37ec9bf55424c064312930ca5f4bde15ee8619ee44e69319aab163", size = 40988851, upload-time = "2025-05-08T16:08:33.671Z" }, - { url = "https://files.pythonhosted.org/packages/1b/e9/7a879c137f7e55b30d75d90ce3eb468197646bc7b443ac036ae3fe109055/scipy-1.15.3-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:3ac07623267feb3ae308487c260ac684b32ea35fd81e12845039952f558047b8", size = 38863011, upload-time = "2025-05-08T16:07:44.039Z" }, - { url = "https://files.pythonhosted.org/packages/51/d1/226a806bbd69f62ce5ef5f3ffadc35286e9fbc802f606a07eb83bf2359de/scipy-1.15.3-cp313-cp313t-macosx_12_0_arm64.whl", hash = "sha256:6487aa99c2a3d509a5227d9a5e889ff05830a06b2ce08ec30df6d79db5fcd5c5", size = 30266407, upload-time = "2025-05-08T16:07:49.891Z" }, - { url = "https://files.pythonhosted.org/packages/e5/9b/f32d1d6093ab9eeabbd839b0f7619c62e46cc4b7b6dbf05b6e615bbd4400/scipy-1.15.3-cp313-cp313t-macosx_14_0_arm64.whl", hash = "sha256:50f9e62461c95d933d5c5ef4a1f2ebf9a2b4e83b0db374cb3f1de104d935922e", size = 22540030, upload-time = "2025-05-08T16:07:54.121Z" }, - { url = "https://files.pythonhosted.org/packages/e7/29/c278f699b095c1a884f29fda126340fcc201461ee8bfea5c8bdb1c7c958b/scipy-1.15.3-cp313-cp313t-macosx_14_0_x86_64.whl", hash = "sha256:14ed70039d182f411ffc74789a16df3835e05dc469b898233a245cdfd7f162cb", size = 25218709, upload-time = "2025-05-08T16:07:58.506Z" }, - { url = "https://files.pythonhosted.org/packages/24/18/9e5374b617aba742a990581373cd6b68a2945d65cc588482749ef2e64467/scipy-1.15.3-cp313-cp313t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0a769105537aa07a69468a0eefcd121be52006db61cdd8cac8a0e68980bbb723", size = 34809045, upload-time = "2025-05-08T16:08:03.929Z" }, - { url = "https://files.pythonhosted.org/packages/e1/fe/9c4361e7ba2927074360856db6135ef4904d505e9b3afbbcb073c4008328/scipy-1.15.3-cp313-cp313t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9db984639887e3dffb3928d118145ffe40eff2fa40cb241a306ec57c219ebbbb", size = 36703062, upload-time = "2025-05-08T16:08:09.558Z" }, - { url = "https://files.pythonhosted.org/packages/b7/8e/038ccfe29d272b30086b25a4960f757f97122cb2ec42e62b460d02fe98e9/scipy-1.15.3-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:40e54d5c7e7ebf1aa596c374c49fa3135f04648a0caabcb66c52884b943f02b4", size = 36393132, upload-time = "2025-05-08T16:08:15.34Z" }, - { url = "https://files.pythonhosted.org/packages/10/7e/5c12285452970be5bdbe8352c619250b97ebf7917d7a9a9e96b8a8140f17/scipy-1.15.3-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:5e721fed53187e71d0ccf382b6bf977644c533e506c4d33c3fb24de89f5c3ed5", size = 38979503, upload-time = "2025-05-08T16:08:21.513Z" }, - { url = "https://files.pythonhosted.org/packages/81/06/0a5e5349474e1cbc5757975b21bd4fad0e72ebf138c5592f191646154e06/scipy-1.15.3-cp313-cp313t-win_amd64.whl", hash = "sha256:76ad1fb5f8752eabf0fa02e4cc0336b4e8f021e2d5f061ed37d6d264db35e3ca", size = 40308097, upload-time = "2025-05-08T16:08:27.627Z" }, -] - [[package]] name = "scipy" version = "1.16.0" source = { registry = "https://pypi.org/simple" } -resolution-markers = [ - "python_full_version >= '3.12'", - "python_full_version == '3.11.*'", -] dependencies = [ - { name = "numpy", marker = "python_full_version >= '3.11'" }, + { name = "numpy" }, ] sdist = { url = "https://files.pythonhosted.org/packages/81/18/b06a83f0c5ee8cddbde5e3f3d0bb9b702abfa5136ef6d4620ff67df7eee5/scipy-1.16.0.tar.gz", hash = "sha256:b5ef54021e832869c8cfb03bc3bf20366cbcd426e02a58e8a58d7584dfbb8f62", size = 30581216, upload-time = "2025-06-22T16:27:55.782Z" } wheels = [ @@ -1708,63 +1437,28 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/e7/9c/0e6afc12c269578be5c0c1c9f4b49a8d32770a080260c333ac04cc1c832d/soupsieve-2.7-py3-none-any.whl", hash = "sha256:6e60cc5c1ffaf1cebcc12e8188320b72071e922c2e897f737cadce79ad5d30c4", size = 36677, upload-time = "2025-04-20T18:50:07.196Z" }, ] -[[package]] -name = "sphinx" -version = "8.1.3" -source = { registry = "https://pypi.org/simple" } -resolution-markers = [ - "python_full_version < '3.11'", -] -dependencies = [ - { name = "alabaster", marker = "python_full_version < '3.11'" }, - { name = "babel", marker = "python_full_version < '3.11'" }, - { name = "colorama", marker = "python_full_version < '3.11' and sys_platform == 'win32'" }, - { name = "docutils", marker = "python_full_version < '3.11'" }, - { name = "imagesize", marker = "python_full_version < '3.11'" }, - { name = "jinja2", marker = "python_full_version < '3.11'" }, - { name = "packaging", marker = "python_full_version < '3.11'" }, - { name = "pygments", marker = "python_full_version < '3.11'" }, - { name = "requests", marker = "python_full_version < '3.11'" }, - { name = "snowballstemmer", marker = "python_full_version < '3.11'" }, - { name = "sphinxcontrib-applehelp", marker = "python_full_version < '3.11'" }, - { name = "sphinxcontrib-devhelp", marker = "python_full_version < '3.11'" }, - { name = "sphinxcontrib-htmlhelp", marker = "python_full_version < '3.11'" }, - { name = "sphinxcontrib-jsmath", marker = "python_full_version < '3.11'" }, - { name = "sphinxcontrib-qthelp", marker = "python_full_version < '3.11'" }, - { name = "sphinxcontrib-serializinghtml", marker = "python_full_version < '3.11'" }, - { name = "tomli", marker = "python_full_version < '3.11'" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/6f/6d/be0b61178fe2cdcb67e2a92fc9ebb488e3c51c4f74a36a7824c0adf23425/sphinx-8.1.3.tar.gz", hash = "sha256:43c1911eecb0d3e161ad78611bc905d1ad0e523e4ddc202a58a821773dc4c927", size = 8184611, upload-time = "2024-10-13T20:27:13.93Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/26/60/1ddff83a56d33aaf6f10ec8ce84b4c007d9368b21008876fceda7e7381ef/sphinx-8.1.3-py3-none-any.whl", hash = "sha256:09719015511837b76bf6e03e42eb7595ac8c2e41eeb9c29c5b755c6b677992a2", size = 3487125, upload-time = "2024-10-13T20:27:10.448Z" }, -] - [[package]] name = "sphinx" version = "8.2.3" source = { registry = "https://pypi.org/simple" } -resolution-markers = [ - "python_full_version >= '3.12'", - "python_full_version == '3.11.*'", -] dependencies = [ - { name = "alabaster", marker = "python_full_version >= '3.11'" }, - { name = "babel", marker = "python_full_version >= '3.11'" }, - { name = "colorama", marker = "python_full_version >= '3.11' and sys_platform == 'win32'" }, - { name = "docutils", marker = "python_full_version >= '3.11'" }, - { name = "imagesize", marker = "python_full_version >= '3.11'" }, - { name = "jinja2", marker = "python_full_version >= '3.11'" }, - { name = "packaging", marker = "python_full_version >= '3.11'" }, - { name = "pygments", marker = "python_full_version >= '3.11'" }, - { name = "requests", marker = "python_full_version >= '3.11'" }, - { name = "roman-numerals-py", marker = "python_full_version >= '3.11'" }, - { name = "snowballstemmer", marker = "python_full_version >= '3.11'" }, - { name = "sphinxcontrib-applehelp", marker = "python_full_version >= '3.11'" }, - { name = "sphinxcontrib-devhelp", marker = "python_full_version >= '3.11'" }, - { name = "sphinxcontrib-htmlhelp", marker = "python_full_version >= '3.11'" }, - { name = "sphinxcontrib-jsmath", marker = "python_full_version >= '3.11'" }, - { name = "sphinxcontrib-qthelp", marker = "python_full_version >= '3.11'" }, - { name = "sphinxcontrib-serializinghtml", marker = "python_full_version >= '3.11'" }, + { name = "alabaster" }, + { name = "babel" }, + { name = "colorama", marker = "sys_platform == 'win32'" }, + { name = "docutils" }, + { name = "imagesize" }, + { name = "jinja2" }, + { name = "packaging" }, + { name = "pygments" }, + { name = "requests" }, + { name = "roman-numerals-py" }, + { name = "snowballstemmer" }, + { name = "sphinxcontrib-applehelp" }, + { name = "sphinxcontrib-devhelp" }, + { name = "sphinxcontrib-htmlhelp" }, + { name = "sphinxcontrib-jsmath" }, + { name = "sphinxcontrib-qthelp" }, + { name = "sphinxcontrib-serializinghtml" }, ] sdist = { url = "https://files.pythonhosted.org/packages/38/ad/4360e50ed56cb483667b8e6dadf2d3fda62359593faabbe749a27c4eaca6/sphinx-8.2.3.tar.gz", hash = "sha256:398ad29dee7f63a75888314e9424d40f52ce5a6a87ae88e7071e80af296ec348", size = 8321876, upload-time = "2025-03-02T22:31:59.658Z" } wheels = [ @@ -1777,8 +1471,7 @@ version = "0.17.4" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "beautifulsoup4" }, - { name = "sphinx", version = "8.1.3", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version < '3.11'" }, - { name = "sphinx", version = "8.2.3", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.11'" }, + { name = "sphinx" }, ] sdist = { url = "https://files.pythonhosted.org/packages/bf/c9/7f909e8d32b3b7920994d80c784fd5b4585e8b2c3ce01386f191244ff670/sphinx_codeautolink-0.17.4.tar.gz", hash = "sha256:44afd4102a1f1517838822f3ddc09d89aade642bb04302d749bb48adc3f2057e", size = 60301, upload-time = "2025-03-07T06:38:03.308Z" } wheels = [ @@ -1790,8 +1483,7 @@ name = "sphinx-copybutton" version = "0.5.2" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "sphinx", version = "8.1.3", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version < '3.11'" }, - { name = "sphinx", version = "8.2.3", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.11'" }, + { name = "sphinx" }, ] sdist = { url = "https://files.pythonhosted.org/packages/fc/2b/a964715e7f5295f77509e59309959f4125122d648f86b4fe7d70ca1d882c/sphinx-copybutton-0.5.2.tar.gz", hash = "sha256:4cf17c82fb9646d1bc9ca92ac280813a3b605d8c421225fd9913154103ee1fbd", size = 23039, upload-time = "2023-04-14T08:10:22.998Z" } wheels = [ @@ -1803,8 +1495,7 @@ name = "sphinx-design" version = "0.6.1" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "sphinx", version = "8.1.3", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version < '3.11'" }, - { name = "sphinx", version = "8.2.3", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.11'" }, + { name = "sphinx" }, ] sdist = { url = "https://files.pythonhosted.org/packages/2b/69/b34e0cb5336f09c6866d53b4a19d76c227cdec1bbc7ac4de63ca7d58c9c7/sphinx_design-0.6.1.tar.gz", hash = "sha256:b44eea3719386d04d765c1a8257caca2b3e6f8421d7b3a5e742c0fd45f84e632", size = 2193689, upload-time = "2024-08-02T13:48:44.277Z" } wheels = [ @@ -1817,8 +1508,7 @@ version = "0.19.0" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "pillow" }, - { name = "sphinx", version = "8.1.3", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version < '3.11'" }, - { name = "sphinx", version = "8.2.3", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.11'" }, + { name = "sphinx" }, ] sdist = { url = "https://files.pythonhosted.org/packages/cd/e5/9ccd6ecd492043123adb465cba504217b9f0a82e2cb5b1d7249c648497c6/sphinx_gallery-0.19.0.tar.gz", hash = "sha256:8400cb5240ad642e28a612fdba0667f725d0505a9be0222d0243de60e8af2eb3", size = 471479, upload-time = "2025-02-13T03:24:50.081Z" } wheels = [ @@ -1830,51 +1520,26 @@ name = "sphinx-issues" version = "5.0.1" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "sphinx", version = "8.1.3", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version < '3.11'" }, - { name = "sphinx", version = "8.2.3", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.11'" }, + { name = "sphinx" }, ] sdist = { url = "https://files.pythonhosted.org/packages/3a/62/b55f1c482ce20acee71185dbebf0497a48d23b325b48925d95d5ce0e4666/sphinx_issues-5.0.1.tar.gz", hash = "sha256:6da131d4545af00be4b48ec7c4086ea82c1371a05116bbe5779f57cff34bf16a", size = 14370, upload-time = "2025-04-10T13:41:41.945Z" } wheels = [ { url = "https://files.pythonhosted.org/packages/e9/22/497d11c8198e00f45bffa6edc275066938dcec76c346facf40a72ff94222/sphinx_issues-5.0.1-py3-none-any.whl", hash = "sha256:58cdd94df25546fa96a224afc9df17063deffaf38336c4a694d2bf478aec75a4", size = 8229, upload-time = "2025-04-10T13:41:40.655Z" }, ] -[[package]] -name = "sphinx-prompt" -version = "1.9.0" -source = { registry = "https://pypi.org/simple" } -resolution-markers = [ - "python_full_version < '3.11'", -] -dependencies = [ - { name = "certifi", marker = "python_full_version < '3.11'" }, - { name = "docutils", marker = "python_full_version < '3.11'" }, - { name = "idna", marker = "python_full_version < '3.11'" }, - { name = "pygments", marker = "python_full_version < '3.11'" }, - { name = "sphinx", version = "8.1.3", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version < '3.11'" }, - { name = "urllib3", marker = "python_full_version < '3.11'" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/34/fe/ac4e24f35b5148b31ac717ae7dcc7a2f7ec56eb729e22c7252ed8ad2d9a5/sphinx_prompt-1.9.0.tar.gz", hash = "sha256:471b3c6d466dce780a9b167d9541865fd4e9a80ed46e31b06a52a0529ae995a1", size = 5340, upload-time = "2024-08-07T15:46:51.428Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/76/98/e90ca466e0ede452d3e5a8d92b8fb68db6de269856e019ed9cab69440522/sphinx_prompt-1.9.0-py3-none-any.whl", hash = "sha256:fd731446c03f043d1ff6df9f22414495b23067c67011cc21658ea8d36b3575fc", size = 7311, upload-time = "2024-08-07T15:46:50.329Z" }, -] - [[package]] name = "sphinx-prompt" version = "1.10.0" source = { registry = "https://pypi.org/simple" } -resolution-markers = [ - "python_full_version >= '3.12'", - "python_full_version == '3.11.*'", -] dependencies = [ - { name = "certifi", marker = "python_full_version >= '3.11'" }, - { name = "docutils", marker = "python_full_version >= '3.11'" }, - { name = "idna", marker = "python_full_version >= '3.11'" }, - { name = "jinja2", marker = "python_full_version >= '3.11'" }, - { name = "pygments", marker = "python_full_version >= '3.11'" }, - { name = "requests", marker = "python_full_version >= '3.11'" }, - { name = "sphinx", version = "8.2.3", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.11'" }, - { name = "urllib3", marker = "python_full_version >= '3.11'" }, + { name = "certifi" }, + { name = "docutils" }, + { name = "idna" }, + { name = "jinja2" }, + { name = "pygments" }, + { name = "requests" }, + { name = "sphinx" }, + { name = "urllib3" }, ] sdist = { url = "https://files.pythonhosted.org/packages/c7/2b/8f3a87784e6313e48b4d91dfb4aae1e5af3fa0c94ef9e875eb2e471e1418/sphinx_prompt-1.10.0.tar.gz", hash = "sha256:23dca4c07ade840c9e87089d79d3499040fa524b3c422941427454e215fdd111", size = 5181, upload-time = "2025-06-24T08:32:18.684Z" } wheels = [ @@ -1887,8 +1552,7 @@ version = "3.0.2" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "docutils" }, - { name = "sphinx", version = "8.1.3", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version < '3.11'" }, - { name = "sphinx", version = "8.2.3", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.11'" }, + { name = "sphinx" }, { name = "sphinxcontrib-jquery" }, ] sdist = { url = "https://files.pythonhosted.org/packages/91/44/c97faec644d29a5ceddd3020ae2edffa69e7d00054a8c7a6021e82f20335/sphinx_rtd_theme-3.0.2.tar.gz", hash = "sha256:b7457bc25dda723b20b086a670b9953c859eab60a2a03ee8eb2bb23e176e5f85", size = 7620463, upload-time = "2024-11-13T11:06:04.545Z" } @@ -1914,8 +1578,7 @@ dependencies = [ { name = "pybtex" }, { name = "pybtex-docutils" }, { name = "setuptools" }, - { name = "sphinx", version = "8.1.3", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version < '3.11'" }, - { name = "sphinx", version = "8.2.3", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.11'" }, + { name = "sphinx" }, ] sdist = { url = "https://files.pythonhosted.org/packages/96/10/237737925e667e79b18ccd81f4a768306b80847fa24b86786f042484b439/sphinxcontrib_bibtex-2.6.4.tar.gz", hash = "sha256:aad018b730d324201f09777f6c25c4a2ff7ac1d5e66af187f21fc21840768760", size = 118453, upload-time = "2025-06-17T06:41:51.22Z" } wheels = [ @@ -1945,8 +1608,7 @@ name = "sphinxcontrib-jquery" version = "4.1" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "sphinx", version = "8.1.3", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version < '3.11'" }, - { name = "sphinx", version = "8.2.3", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.11'" }, + { name = "sphinx" }, ] sdist = { url = "https://files.pythonhosted.org/packages/de/f3/aa67467e051df70a6330fe7770894b3e4f09436dea6881ae0b4f3d87cad8/sphinxcontrib-jquery-4.1.tar.gz", hash = "sha256:1620739f04e36a2c779f1a131a2dfd49b2fd07351bf1968ced074365933abc7a", size = 122331, upload-time = "2023-03-14T15:01:01.944Z" } wheels = [ @@ -2089,22 +1751,6 @@ dependencies = [ ] sdist = { url = "https://files.pythonhosted.org/packages/ed/f6/2ac0287b442160a89d726b17a9184a4c615bb5237db763791a7fd16d9df1/zstandard-0.23.0.tar.gz", hash = "sha256:b2d8c62d08e7255f68f7a740bae85b3c9b8e5466baa9cbf7f57f1cde0ac6bc09", size = 681701, upload-time = "2024-07-15T00:18:06.141Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/2a/55/bd0487e86679db1823fc9ee0d8c9c78ae2413d34c0b461193b5f4c31d22f/zstandard-0.23.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:bf0a05b6059c0528477fba9054d09179beb63744355cab9f38059548fedd46a9", size = 788701, upload-time = "2024-07-15T00:13:27.351Z" }, - { url = "https://files.pythonhosted.org/packages/e1/8a/ccb516b684f3ad987dfee27570d635822e3038645b1a950c5e8022df1145/zstandard-0.23.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:fc9ca1c9718cb3b06634c7c8dec57d24e9438b2aa9a0f02b8bb36bf478538880", size = 633678, upload-time = "2024-07-15T00:13:30.24Z" }, - { url = "https://files.pythonhosted.org/packages/12/89/75e633d0611c028e0d9af6df199423bf43f54bea5007e6718ab7132e234c/zstandard-0.23.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:77da4c6bfa20dd5ea25cbf12c76f181a8e8cd7ea231c673828d0386b1740b8dc", size = 4941098, upload-time = "2024-07-15T00:13:32.526Z" }, - { url = "https://files.pythonhosted.org/packages/4a/7a/bd7f6a21802de358b63f1ee636ab823711c25ce043a3e9f043b4fcb5ba32/zstandard-0.23.0-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:b2170c7e0367dde86a2647ed5b6f57394ea7f53545746104c6b09fc1f4223573", size = 5308798, upload-time = "2024-07-15T00:13:34.925Z" }, - { url = "https://files.pythonhosted.org/packages/79/3b/775f851a4a65013e88ca559c8ae42ac1352db6fcd96b028d0df4d7d1d7b4/zstandard-0.23.0-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:c16842b846a8d2a145223f520b7e18b57c8f476924bda92aeee3a88d11cfc391", size = 5341840, upload-time = "2024-07-15T00:13:37.376Z" }, - { url = "https://files.pythonhosted.org/packages/09/4f/0cc49570141dd72d4d95dd6fcf09328d1b702c47a6ec12fbed3b8aed18a5/zstandard-0.23.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:157e89ceb4054029a289fb504c98c6a9fe8010f1680de0201b3eb5dc20aa6d9e", size = 5440337, upload-time = "2024-07-15T00:13:39.772Z" }, - { url = "https://files.pythonhosted.org/packages/e7/7c/aaa7cd27148bae2dc095191529c0570d16058c54c4597a7d118de4b21676/zstandard-0.23.0-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:203d236f4c94cd8379d1ea61db2fce20730b4c38d7f1c34506a31b34edc87bdd", size = 4861182, upload-time = "2024-07-15T00:13:42.495Z" }, - { url = "https://files.pythonhosted.org/packages/ac/eb/4b58b5c071d177f7dc027129d20bd2a44161faca6592a67f8fcb0b88b3ae/zstandard-0.23.0-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:dc5d1a49d3f8262be192589a4b72f0d03b72dcf46c51ad5852a4fdc67be7b9e4", size = 4932936, upload-time = "2024-07-15T00:13:44.234Z" }, - { url = "https://files.pythonhosted.org/packages/44/f9/21a5fb9bb7c9a274b05ad700a82ad22ce82f7ef0f485980a1e98ed6e8c5f/zstandard-0.23.0-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:752bf8a74412b9892f4e5b58f2f890a039f57037f52c89a740757ebd807f33ea", size = 5464705, upload-time = "2024-07-15T00:13:46.822Z" }, - { url = "https://files.pythonhosted.org/packages/49/74/b7b3e61db3f88632776b78b1db597af3f44c91ce17d533e14a25ce6a2816/zstandard-0.23.0-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:80080816b4f52a9d886e67f1f96912891074903238fe54f2de8b786f86baded2", size = 4857882, upload-time = "2024-07-15T00:13:49.297Z" }, - { url = "https://files.pythonhosted.org/packages/4a/7f/d8eb1cb123d8e4c541d4465167080bec88481ab54cd0b31eb4013ba04b95/zstandard-0.23.0-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:84433dddea68571a6d6bd4fbf8ff398236031149116a7fff6f777ff95cad3df9", size = 4697672, upload-time = "2024-07-15T00:13:51.447Z" }, - { url = "https://files.pythonhosted.org/packages/5e/05/f7dccdf3d121309b60342da454d3e706453a31073e2c4dac8e1581861e44/zstandard-0.23.0-cp310-cp310-musllinux_1_2_ppc64le.whl", hash = "sha256:ab19a2d91963ed9e42b4e8d77cd847ae8381576585bad79dbd0a8837a9f6620a", size = 5206043, upload-time = "2024-07-15T00:13:53.587Z" }, - { url = "https://files.pythonhosted.org/packages/86/9d/3677a02e172dccd8dd3a941307621c0cbd7691d77cb435ac3c75ab6a3105/zstandard-0.23.0-cp310-cp310-musllinux_1_2_s390x.whl", hash = "sha256:59556bf80a7094d0cfb9f5e50bb2db27fefb75d5138bb16fb052b61b0e0eeeb0", size = 5667390, upload-time = "2024-07-15T00:13:56.137Z" }, - { url = "https://files.pythonhosted.org/packages/41/7e/0012a02458e74a7ba122cd9cafe491facc602c9a17f590367da369929498/zstandard-0.23.0-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:27d3ef2252d2e62476389ca8f9b0cf2bbafb082a3b6bfe9d90cbcbb5529ecf7c", size = 5198901, upload-time = "2024-07-15T00:13:58.584Z" }, - { url = "https://files.pythonhosted.org/packages/65/3a/8f715b97bd7bcfc7342d8adcd99a026cb2fb550e44866a3b6c348e1b0f02/zstandard-0.23.0-cp310-cp310-win32.whl", hash = "sha256:5d41d5e025f1e0bccae4928981e71b2334c60f580bdc8345f824e7c0a4c2a813", size = 430596, upload-time = "2024-07-15T00:14:00.693Z" }, - { url = "https://files.pythonhosted.org/packages/19/b7/b2b9eca5e5a01111e4fe8a8ffb56bdcdf56b12448a24effe6cfe4a252034/zstandard-0.23.0-cp310-cp310-win_amd64.whl", hash = "sha256:519fbf169dfac1222a76ba8861ef4ac7f0530c35dd79ba5727014613f91613d4", size = 495498, upload-time = "2024-07-15T00:14:02.741Z" }, { url = "https://files.pythonhosted.org/packages/9e/40/f67e7d2c25a0e2dc1744dd781110b0b60306657f8696cafb7ad7579469bd/zstandard-0.23.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:34895a41273ad33347b2fc70e1bff4240556de3c46c6ea430a7ed91f9042aa4e", size = 788699, upload-time = "2024-07-15T00:14:04.909Z" }, { url = "https://files.pythonhosted.org/packages/e8/46/66d5b55f4d737dd6ab75851b224abf0afe5774976fe511a54d2eb9063a41/zstandard-0.23.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:77ea385f7dd5b5676d7fd943292ffa18fbf5c72ba98f7d09fc1fb9e819b34c23", size = 633681, upload-time = "2024-07-15T00:14:13.99Z" }, { url = "https://files.pythonhosted.org/packages/63/b6/677e65c095d8e12b66b8f862b069bcf1f1d781b9c9c6f12eb55000d57583/zstandard-0.23.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:983b6efd649723474f29ed42e1467f90a35a74793437d0bc64a5bf482bedfa0a", size = 4944328, upload-time = "2024-07-15T00:14:16.588Z" }, From 8a931b595205366f57975b5220ce89bcd25f3503 Mon Sep 17 00:00:00 2001 From: Felix Soubelet Date: Thu, 8 Jan 2026 11:01:35 +0100 Subject: [PATCH 04/70] type settings dicts --- pyhdtoolkit/utils/htc_monitor.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pyhdtoolkit/utils/htc_monitor.py b/pyhdtoolkit/utils/htc_monitor.py index 3f5f0b5c..bb819058 100644 --- a/pyhdtoolkit/utils/htc_monitor.py +++ b/pyhdtoolkit/utils/htc_monitor.py @@ -34,7 +34,7 @@ # ----- Data ----- # -TASK_COLUMNS_SETTINGS = { +TASK_COLUMNS_SETTINGS: dict[str, dict[str, str | bool]] = { "OWNER": {"justify": "left", "header_style": "bold", "style": "bold", "no_wrap": True}, "BATCH_NAME": {"justify": "center", "header_style": "magenta", "style": "magenta", "no_wrap": True}, "SUBMITTED": { @@ -55,7 +55,7 @@ "JOB_IDS": {"justify": "right", "no_wrap": True}, } -CLUSTER_COLUMNS_SETTINGS = { +CLUSTER_COLUMNS_SETTINGS: dict[str, dict[str, str | bool]] = { "SOURCE": {"justify": "left", "header_style": "bold", "style": "bold", "no_wrap": True}, "JOBS": {"justify": "right", "header_style": "bold", "style": "bold", "no_wrap": True}, "COMPLETED": {"justify": "right", "header_style": "bold green3", "style": "bold green3", "no_wrap": True}, From 1be00b4d938b0098a3627c89b2c35eda61171367 Mon Sep 17 00:00:00 2001 From: Felix Soubelet Date: Thu, 8 Jan 2026 11:04:49 +0100 Subject: [PATCH 05/70] do not expose entrypoint module in init - might be a script folder at some point --- pyhdtoolkit/utils/__init__.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pyhdtoolkit/utils/__init__.py b/pyhdtoolkit/utils/__init__.py index 8f081037..6e1cdc77 100644 --- a/pyhdtoolkit/utils/__init__.py +++ b/pyhdtoolkit/utils/__init__.py @@ -1,3 +1,3 @@ -from . import cmdline, contexts, decorators, htc_monitor, logging # noqa: TID252 +from . import cmdline, contexts, decorators, logging # noqa: TID252 -__all__ = ["cmdline", "contexts", "decorators", "htc_monitor", "logging"] +__all__ = ["cmdline", "contexts", "decorators", "logging"] From 974865168c9829f468e5c1ba04b9588dce777c6e Mon Sep 17 00:00:00 2001 From: Felix Soubelet Date: Thu, 8 Jan 2026 11:06:49 +0100 Subject: [PATCH 06/70] declare the entrypoint as a script in metadata --- pyproject.toml | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/pyproject.toml b/pyproject.toml index 6c5f130d..36bfae1e 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -17,6 +17,8 @@ exclude = [ [tool.hatch.build.targets.wheel] packages = ["pyhdtoolkit"] +# -- Project Metadata -- # + [project] name = "pyhdtoolkit" readme = "README.md" @@ -107,6 +109,9 @@ all = [ "pyhdtoolkit[monitor]", ] +[project.scripts] +htc-monitor = "pyhdtoolkit.utils.htc_monitor:main" + [project.urls] homepage = "https://github.com/fsoubelet/PyhDToolkit" repository = "https://github.com/fsoubelet/PyhDToolkit" From df0f61e200a81710d9dc5957478a40892f8cf0db Mon Sep 17 00:00:00 2001 From: Felix Soubelet Date: Thu, 8 Jan 2026 11:08:45 +0100 Subject: [PATCH 07/70] I dont use isort and black anymore --- pyproject.toml | 41 +++-------------------------------------- 1 file changed, 3 insertions(+), 38 deletions(-) diff --git a/pyproject.toml b/pyproject.toml index 36bfae1e..97e31637 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -17,7 +17,7 @@ exclude = [ [tool.hatch.build.targets.wheel] packages = ["pyhdtoolkit"] -# -- Project Metadata -- # +# ----- Project Metadata ----- # [project] name = "pyhdtoolkit" @@ -76,15 +76,15 @@ monitor = [ "pendulum >= 3.0", ] test = [ + "pyhdtoolkit[monitor]", # htc stuff is tested "pytest >= 8.0", "pytest-cov >= 6.0", "pytest-xdist >= 3.0", - "numba >= 0.60.0", + "numba >= 0.60.0", # for @maybe_jit "flaky >= 3.5", "pytest-randomly >= 3.10", "coverage[toml] >= 7.0", "pytest-mpl >= 0.14", - "pyhdtoolkit[monitor]", ] dev = [ "ruff >= 0.12", @@ -146,41 +146,6 @@ precision = 2 # ----- Dev Tools Configuration ----- # -[tool.isort] -atomic = true -ensure_newline_before_comments = true -filter_files = true -force_grid_wrap = 0 -force_single_line = false -include_trailing_comma = true -known_first_party = "pyhdtoolkit" -known_third_party = "pytest" -line_length = 110 -lines_between_types = 1 -multi_line_output = 3 -use_parentheses = true -profile = "black" - -[tool.black] -line-length = 120 -include = '\.pyi?$' -exclude = ''' -/( - \.eggs - | \.git - | \.hg - | \.mypy_cache - | \.tox - | \.venv - | _build - | buck-out - | build - | dist - | tests/.*/setup.py - | acc-models-lhc -)/ -''' - [tool.ruff] target-version = "py311" # Assume Python 3.11+. line-length = 120 From 992a368503d13183b7d5cacc419814583a9b9de2 Mon Sep 17 00:00:00 2001 From: Felix Soubelet Date: Thu, 8 Jan 2026 11:17:28 +0100 Subject: [PATCH 08/70] raise if no scheduler information matched (instead of crashing) --- pyhdtoolkit/utils/htc_monitor.py | 15 ++++++++++++--- 1 file changed, 12 insertions(+), 3 deletions(-) diff --git a/pyhdtoolkit/utils/htc_monitor.py b/pyhdtoolkit/utils/htc_monitor.py index bb819058..d08b3729 100644 --- a/pyhdtoolkit/utils/htc_monitor.py +++ b/pyhdtoolkit/utils/htc_monitor.py @@ -14,7 +14,6 @@ one shoule be able to build a different monitor script from the functions in here. """ - import re import time @@ -251,9 +250,19 @@ def _process_scheduler_information_line(line: str) -> str: ------- str The scheduler name extracted from the input line. + + Raises + ------ + ValueError + If the scheduler information could not be extracted + from the input line. This typically happens when no + jobs are present in the HTCondor queue and condor_q + returns empty lines. """ - result = re.search(r"Schedd: (.*).cern.ch", line) - return result.group(1) + match: re.Match[str] | None = re.search(r"Schedd: (.*).cern.ch", line) + if match is None: + raise ValueError("Could not extract scheduler information from HTCondor output.") + return match.group(1) def _process_task_summary_line(line: str) -> HTCTaskSummary: From cd7d0edb4d08f6ba8b70526ba8b7870bb6c3f50f Mon Sep 17 00:00:00 2001 From: Felix Soubelet Date: Thu, 8 Jan 2026 11:17:38 +0100 Subject: [PATCH 09/70] properly escape dots in the regex --- pyhdtoolkit/utils/htc_monitor.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pyhdtoolkit/utils/htc_monitor.py b/pyhdtoolkit/utils/htc_monitor.py index d08b3729..4f10cbe2 100644 --- a/pyhdtoolkit/utils/htc_monitor.py +++ b/pyhdtoolkit/utils/htc_monitor.py @@ -259,7 +259,7 @@ def _process_scheduler_information_line(line: str) -> str: jobs are present in the HTCondor queue and condor_q returns empty lines. """ - match: re.Match[str] | None = re.search(r"Schedd: (.*).cern.ch", line) + match: re.Match[str] | None = re.search(r"Schedd: (.*)\.cern\.ch", line) if match is None: raise ValueError("Could not extract scheduler information from HTCondor output.") return match.group(1) From 62af7b7a705a76459c71f2593ba2b9ab41beafa6 Mon Sep 17 00:00:00 2001 From: Felix Soubelet Date: Thu, 8 Jan 2026 11:18:09 +0100 Subject: [PATCH 10/70] less greedy capture --- pyhdtoolkit/utils/htc_monitor.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pyhdtoolkit/utils/htc_monitor.py b/pyhdtoolkit/utils/htc_monitor.py index 4f10cbe2..ccddefbf 100644 --- a/pyhdtoolkit/utils/htc_monitor.py +++ b/pyhdtoolkit/utils/htc_monitor.py @@ -259,7 +259,7 @@ def _process_scheduler_information_line(line: str) -> str: jobs are present in the HTCondor queue and condor_q returns empty lines. """ - match: re.Match[str] | None = re.search(r"Schedd: (.*)\.cern\.ch", line) + match: re.Match[str] | None = re.search(r"Schedd:\s+([^.]+)\.cern\.ch", line) if match is None: raise ValueError("Could not extract scheduler information from HTCondor output.") return match.group(1) From 167dda71e5a9ec3ff0382a0b7f35f2056f8e6df8 Mon Sep 17 00:00:00 2001 From: Felix Soubelet Date: Thu, 8 Jan 2026 11:20:38 +0100 Subject: [PATCH 11/70] compile the pattern once --- pyhdtoolkit/utils/htc_monitor.py | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/pyhdtoolkit/utils/htc_monitor.py b/pyhdtoolkit/utils/htc_monitor.py index ccddefbf..06effb6d 100644 --- a/pyhdtoolkit/utils/htc_monitor.py +++ b/pyhdtoolkit/utils/htc_monitor.py @@ -31,7 +31,12 @@ config_logger(level="ERROR") -# ----- Data ----- # +# ----- Caching ------ # + +# We compile our regex pattern once only +_SCHEDD_RE: re.Pattern[str] = re.compile(r"Schedd:\s+([^.]+)\.cern\.ch") + +# ----- Settings ----- # TASK_COLUMNS_SETTINGS: dict[str, dict[str, str | bool]] = { "OWNER": {"justify": "left", "header_style": "bold", "style": "bold", "no_wrap": True}, @@ -259,7 +264,7 @@ def _process_scheduler_information_line(line: str) -> str: jobs are present in the HTCondor queue and condor_q returns empty lines. """ - match: re.Match[str] | None = re.search(r"Schedd:\s+([^.]+)\.cern\.ch", line) + match: re.Match[str] | None = _SCHEDD_RE.search(line) if match is None: raise ValueError("Could not extract scheduler information from HTCondor output.") return match.group(1) From ac60e6ed998d394f10aa5b710d0151b834071d67 Mon Sep 17 00:00:00 2001 From: Felix Soubelet Date: Thu, 8 Jan 2026 11:26:54 +0100 Subject: [PATCH 12/70] rename and will only be utility module --- pyhdtoolkit/utils/{htc_monitor.py => htcondor.py} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename pyhdtoolkit/utils/{htc_monitor.py => htcondor.py} (100%) diff --git a/pyhdtoolkit/utils/htc_monitor.py b/pyhdtoolkit/utils/htcondor.py similarity index 100% rename from pyhdtoolkit/utils/htc_monitor.py rename to pyhdtoolkit/utils/htcondor.py From 7a9631678a23505c51a9b4fc6a520a2bde9c29ce Mon Sep 17 00:00:00 2001 From: Felix Soubelet Date: Thu, 8 Jan 2026 11:28:55 +0100 Subject: [PATCH 13/70] new script, barebones now, with entrypoint --- pyhdtoolkit/scripts/htc_monitor.py | 64 +++++ pyhdtoolkit/utils/htc_monitor.py | 435 +++++++++++++++++++++++++++++ 2 files changed, 499 insertions(+) create mode 100644 pyhdtoolkit/scripts/htc_monitor.py create mode 100644 pyhdtoolkit/utils/htc_monitor.py diff --git a/pyhdtoolkit/scripts/htc_monitor.py b/pyhdtoolkit/scripts/htc_monitor.py new file mode 100644 index 00000000..ea8a2bb4 --- /dev/null +++ b/pyhdtoolkit/scripts/htc_monitor.py @@ -0,0 +1,64 @@ +import time + +from loguru import logger +from rich.console import Group +from rich.live import Live +from rich.panel import Panel + +from pyhdtoolkit.utils.htc_monitor import _make_cluster_table, _make_tasks_table, query_condor_q, read_condor_q +from pyhdtoolkit.utils.logging import config_logger + +config_logger(level="ERROR") + +@logger.catch() +def main(): + def generate_renderable() -> Group: + """ + .. versionadded:: 0.9.0 + + Function called to update the live display, + fetches data from htcondor, does the processing + and returns a Group with both Panels. + + Returns + ------- + rich.console.Group + A `rich.console.Group` object with two + `rich.panel.Panel` objects inside, one + holding the tasks table and the other + holding the cluster information. + """ + condor_string = query_condor_q() + user_tasks, cluster_info = read_condor_q(condor_string) + owner = user_tasks[0].owner if user_tasks else "User" + + tasks_table = _make_tasks_table(user_tasks) + cluster_table = _make_cluster_table(owner, cluster_info) + return Group( + Panel( + tasks_table, + title=f"Scheduler: {cluster_info.scheduler_id}.cern.ch", + expand=False, + border_style="scope.border", + ), + Panel( + cluster_table, + title=f"{cluster_info.scheduler_id} Statistics", + expand=False, + border_style="scope.border", + ), + ) + + with Live(generate_renderable(), refresh_per_second=0.25) as live: + live.console.log("Querying HTCondor Queue - Refreshed Every 5 Minutes\n") + while True: + try: + live.update(generate_renderable()) + time.sleep(300) + except KeyboardInterrupt: + live.console.log("Exiting Program") + break + + +if __name__ == "__main__": + main() diff --git a/pyhdtoolkit/utils/htc_monitor.py b/pyhdtoolkit/utils/htc_monitor.py new file mode 100644 index 00000000..06effb6d --- /dev/null +++ b/pyhdtoolkit/utils/htc_monitor.py @@ -0,0 +1,435 @@ +""" +.. _utils-htc-monitor: + +HTCondor Monitoring +------------------- + +A module with utility to query the HTCondor queue, process +the returned data and display it nicely. + +Note +---- + This module is meant to be called as a script, but some + of the individual functionality is made public API and + one shoule be able to build a different monitor script + from the functions in here. +""" +import re +import time + +import pendulum +from loguru import logger +from rich import box +from rich.console import Group +from rich.live import Live +from rich.panel import Panel +from rich.table import Table + +from pyhdtoolkit.models.htc import BaseSummary, ClusterSummary, HTCTaskSummary +from pyhdtoolkit.utils.cmdline import CommandLine +from pyhdtoolkit.utils.logging import config_logger + +config_logger(level="ERROR") + +# ----- Caching ------ # + +# We compile our regex pattern once only +_SCHEDD_RE: re.Pattern[str] = re.compile(r"Schedd:\s+([^.]+)\.cern\.ch") + +# ----- Settings ----- # + +TASK_COLUMNS_SETTINGS: dict[str, dict[str, str | bool]] = { + "OWNER": {"justify": "left", "header_style": "bold", "style": "bold", "no_wrap": True}, + "BATCH_NAME": {"justify": "center", "header_style": "magenta", "style": "magenta", "no_wrap": True}, + "SUBMITTED": { + "justify": "center", + "header_style": "medium_turquoise", + "style": "medium_turquoise", + "no_wrap": True, + }, + "DONE": {"justify": "right", "header_style": "bold green3", "style": "bold green3", "no_wrap": True}, + "RUNNING": { + "justify": "right", + "header_style": "bold cornflower_blue", + "style": "bold cornflower_blue", + "no_wrap": True, + }, + "IDLE": {"justify": "right", "header_style": "bold dark_orange3", "style": "bold dark_orange3", "no_wrap": True}, + "TOTAL": {"justify": "right", "style": "bold", "no_wrap": True}, + "JOB_IDS": {"justify": "right", "no_wrap": True}, +} + +CLUSTER_COLUMNS_SETTINGS: dict[str, dict[str, str | bool]] = { + "SOURCE": {"justify": "left", "header_style": "bold", "style": "bold", "no_wrap": True}, + "JOBS": {"justify": "right", "header_style": "bold", "style": "bold", "no_wrap": True}, + "COMPLETED": {"justify": "right", "header_style": "bold green3", "style": "bold green3", "no_wrap": True}, + "RUNNING": { + "justify": "right", + "header_style": "bold cornflower_blue", + "style": "bold cornflower_blue", + "no_wrap": True, + }, + "IDLE": {"justify": "right", "header_style": "bold dark_orange3", "style": "bold dark_orange3", "no_wrap": True}, + "HELD": {"justify": "right", "header_style": "bold gold1", "style": "bold gold1", "no_wrap": True}, + "SUSPENDED": {"justify": "right", "header_style": "bold slate_blue1", "style": "bold slate_blue1", "no_wrap": True}, + "REMOVED": {"justify": "right", "header_style": "bold red3", "style": "bold red3", "no_wrap": True}, +} + + +# ----- HTCondor Querying / Processing ----- # + + +def query_condor_q() -> str: + """ + .. versionadded:: 0.9.0 + + Returns a decoded string with the result of the + ``condor_q`` command, to get the status of the + caller' jobs. + + Returns + ------- + str + The utf-8 decoded string returned by the + ``condor_q`` command. + """ + return_code, raw_result = CommandLine.run("condor_q") + condor_status = raw_result.decode().strip() + if return_code == 0: + return condor_status + + # An issue occured, let's raise + msg = "Checking htcondor status failed" + raise ChildProcessError(msg) + + +def read_condor_q(report: str) -> tuple[list[HTCTaskSummary], ClusterSummary]: + """ + .. versionadded:: 0.9.0 + + Splits information from different parts of the ``condor_q`` + command's output into one clean, validated data structures. + + Parameters + ---------- + report : str + The utf-8 decoded string returned by the ``condor_q`` + command, as returned by `query_condor_q` . + + Returns + ------- + tuple[list[HTCTaskSummary], ClusterSummary] + A tuple with two elements. The first element is a list of + each task summary given by ``condor_q``, as a validated + `~.models.htc.HTCTaskSummary`. The second element is a + validated `~.models.htc.ClusterSummary` object with the + scheduler identification and summaries of the user as well + as all users' statistics on this scheduler cluster. + + Example + ------- + .. code-block:: python + + condor_q_output = get_the_string_as_you_wish(...) + tasks, cluster = read_condor_q(condor_q_output) + """ + tasks: list[HTCTaskSummary] = [] + next_line_is_task_report = False + + for line in report.splitlines(): + if line.startswith("-- Schedd:"): # extract scheduler information + scheduler_id = _process_scheduler_information_line(line) + + elif line.startswith("OWNER"): # headers line before we get task reports + next_line_is_task_report = True + + elif next_line_is_task_report: # extract task report information + if line not in ("\n", ""): + tasks.append(_process_task_summary_line(line)) + else: # an empty line denotes the end of the task report(s) + next_line_is_task_report = False + + else: # extract cluster information, only 3 lines here + querying_owner = tasks[0].owner if tasks else r"(\D+)" + if "query" in line: # first line + query_summary = _process_cluster_summary_line(line, "query") + elif "all users" in line: # last line + full_summary = _process_cluster_summary_line(line, "all users") + elif line not in ("\n", ""): # user line, whoever the user is + owner_summary = _process_cluster_summary_line(line, querying_owner) + cluster_summary = ClusterSummary( + scheduler_id=scheduler_id, query=query_summary, user=owner_summary, cluster=full_summary + ) + return tasks, cluster_summary + + +# ----- Output Formating ----- # + + +def _make_tasks_table(tasks: list[HTCTaskSummary]) -> Table: + """ + Takes the list of `~.models.htc.HTCTaskSummary` models + as returned by `read_condor_q` and from the information + within creates a `rich.table.Table`. Each row of the + table represents one `HTCTaskSummary` from the input. + The returned object is ready to be displayed by `rich`. + + Parameters + ---------- + tasks : list[HTCTaskSummary] + A list of `~.models.htc.HTCTaskSummary` models, as + parsed from the output of the ``condor_q`` command. + + Returns + ------- + rich.table.Table + A `rich.table.Table` object with the tasks information + formatted and ready to be displayed by `rich`. + """ + table = _default_tasks_table() + date_display_format = "dddd, D MMM YY at LT (zz)" # example: Wednesday, 21 Apr 21 9:04 PM (CEST) + for task in tasks: + table.add_row( + task.owner, + str(task.batch_name), + task.submitted.format(fmt=date_display_format), + str(task.done), + str(task.run), + str(task.idle), + str(task.total), + task.job_ids, + ) + return table + + +def _make_cluster_table(owner_name: str, cluster: ClusterSummary) -> Table: + """ + Takes a `~.models.htc.ClusterSummary` model as returned by + `read_condor_q` and from the information within creates a + `rich.table.Table`. The returned object is ready to be + displayed by `rich`. + + Parameters + ---------- + owner_name : str + The name of the user who queried the HTCondor queue. + cluster : ClusterSummary + A `~.models.htc.ClusterSummary` model, as parsed from + the output of the ``condor_q`` command. + + Returns + ------- + rich.table.Table + A `rich.table.Table` object with the cluster information + formatted and ready to be displayed by `rich`. + """ + table = _default_cluster_table() + for i, source in enumerate(["query", "user", "cluster"]): + table.add_row( + "Query" if i == 0 else ("All Users" if i == 2 else owner_name), # noqa: PLR2004 + str(cluster.model_dump()[source]["jobs"]), + str(cluster.model_dump()[source]["completed"]), + str(cluster.model_dump()[source]["running"]), + str(cluster.model_dump()[source]["idle"]), + str(cluster.model_dump()[source]["held"]), + str(cluster.model_dump()[source]["suspended"]), + str(cluster.model_dump()[source]["removed"]), + ) + return table + + +# ----- Helpers ----- # + + +def _process_scheduler_information_line(line: str) -> str: + """ + Extract only the 'Schedd: .cern.ch' part + of the scheduler information line. + + Parameters + ---------- + line : str + The line containing the scheduler information. + + Returns + ------- + str + The scheduler name extracted from the input line. + + Raises + ------ + ValueError + If the scheduler information could not be extracted + from the input line. This typically happens when no + jobs are present in the HTCondor queue and condor_q + returns empty lines. + """ + match: re.Match[str] | None = _SCHEDD_RE.search(line) + if match is None: + raise ValueError("Could not extract scheduler information from HTCondor output.") + return match.group(1) + + +def _process_task_summary_line(line: str) -> HTCTaskSummary: + """ + Extract the various information in a task summary line, + validated and returned as an `HTCTaskSummary` object. + + Parameters + ---------- + line : str + The line containing the task summary information. + + Returns + ------- + pyhdtoolkit.models.htc.HTCTaskSummary + The task summary information as a validated + `~.models.htc.HTCTaskSummary` object. + """ + line_elements = line.split() + return HTCTaskSummary( + owner=line_elements[0], + batch_name=line_elements[2], # line_elements[1] is the 'ID:' part, we don't need it + submitted=pendulum.from_format( + f"{line_elements[3]} {line_elements[4]}", fmt="MM/D HH:mm", tz="Europe/Paris" + ), # Geneva timezone is Paris timezone, + done=line_elements[5], + run=line_elements[6], + idle=line_elements[7], + total=line_elements[8], + job_ids=line_elements[9], + ) + + +def _process_cluster_summary_line(line: str, query: str | None = None) -> BaseSummary: + r""" + Extract the various information in a cluster summary line, + validated and returned as a `~.models.htc.BaseSummary`. + + Note + ---- + Beware if no jobs are running we can't have taken the + ``querying_owner`` info from tasks summaries, so we need + to match a wildcard word by giving querying_owner=(\D+). + This would add a match to the regex search, and we need + to look one match further for the wanted information. + + Parameters + ---------- + line : str + The line containing the cluster summary information. + query : str, optional + The name of the user who queried the HTCondor queue. + + Returns + ------- + pyhdtoolkit.models.htc.BaseSummary + The cluster summary information as a validated + `~.models.htc.BaseSummary` object. + """ + result = re.search( + rf"Total for {query}: (\d+) jobs; (\d+) completed, " + r"(\d+) removed, (\d+) idle, (\d+) running, (\d+) held, (\d+) suspended", + line, + ) + first_interesting_match_index = 1 if query != r"(\D+)" else 2 + return BaseSummary( + jobs=result.group(first_interesting_match_index), + completed=result.group(first_interesting_match_index + 1), + removed=result.group(first_interesting_match_index + 2), + idle=result.group(first_interesting_match_index + 3), + running=result.group(first_interesting_match_index + 4), + held=result.group(first_interesting_match_index + 5), + suspended=result.group(first_interesting_match_index + 6), + ) + + +def _default_tasks_table() -> Table: + """ + Create the default structure for the Tasks + Table, hard coded columns and no rows added. + + Returns + ------- + rich.table.Table + A `rich.table.Table` object with the + default structure for the Tasks Table. + """ + table = Table(width=120, box=box.SIMPLE_HEAVY) + for header, header_col_settings in TASK_COLUMNS_SETTINGS.items(): + table.add_column(header, **header_col_settings) + return table + + +def _default_cluster_table() -> Table: + """ + Create the default structure for the Cluster + Table, hard coded columns and no rows added. + + Returns + ------- + rich.table.Table + A `rich.table.Table` object with the + default structure for the Cluster Table. + """ + table = Table(width=120, box=box.HORIZONTALS) + for header, header_col_settings in CLUSTER_COLUMNS_SETTINGS.items(): + table.add_column(header, **header_col_settings) + return table + + +# ----- Executable ----- # + + +@logger.catch() +def main(): + def generate_renderable() -> Group: + """ + .. versionadded:: 0.9.0 + + Function called to update the live display, + fetches data from htcondor, does the processing + and returns a Group with both Panels. + + Returns + ------- + rich.console.Group + A `rich.console.Group` object with two + `rich.panel.Panel` objects inside, one + holding the tasks table and the other + holding the cluster information. + """ + condor_string = query_condor_q() + user_tasks, cluster_info = read_condor_q(condor_string) + owner = user_tasks[0].owner if user_tasks else "User" + + tasks_table = _make_tasks_table(user_tasks) + cluster_table = _make_cluster_table(owner, cluster_info) + return Group( + Panel( + tasks_table, + title=f"Scheduler: {cluster_info.scheduler_id}.cern.ch", + expand=False, + border_style="scope.border", + ), + Panel( + cluster_table, + title=f"{cluster_info.scheduler_id} Statistics", + expand=False, + border_style="scope.border", + ), + ) + + with Live(generate_renderable(), refresh_per_second=0.25) as live: + live.console.log("Querying HTCondor Queue - Refreshed Every 5 Minutes\n") + while True: + try: + live.update(generate_renderable()) + time.sleep(300) + except KeyboardInterrupt: + live.console.log("Exiting Program") + break + + +if __name__ == "__main__": + main() From 5cd15f5649326180d8ae7bcf97a9fd9c784c0504 Mon Sep 17 00:00:00 2001 From: Felix Soubelet Date: Thu, 8 Jan 2026 11:47:10 +0100 Subject: [PATCH 14/70] adapt script from project metadata to be taking from new script --- pyproject.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pyproject.toml b/pyproject.toml index 97e31637..5e8af067 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -110,7 +110,7 @@ all = [ ] [project.scripts] -htc-monitor = "pyhdtoolkit.utils.htc_monitor:main" +htc-monitor = "pyhdtoolkit.scripts.htc_monitor:main" [project.urls] homepage = "https://github.com/fsoubelet/PyhDToolkit" From 2de80a100817934b77f58b9508749a5d26b7052b Mon Sep 17 00:00:00 2001 From: Felix Soubelet Date: Thu, 8 Jan 2026 11:48:41 +0100 Subject: [PATCH 15/70] remove old util, remove entrypoint from new util --- pyhdtoolkit/utils/htc_monitor.py | 435 ------------------------------- pyhdtoolkit/utils/htcondor.py | 65 ----- 2 files changed, 500 deletions(-) delete mode 100644 pyhdtoolkit/utils/htc_monitor.py diff --git a/pyhdtoolkit/utils/htc_monitor.py b/pyhdtoolkit/utils/htc_monitor.py deleted file mode 100644 index 06effb6d..00000000 --- a/pyhdtoolkit/utils/htc_monitor.py +++ /dev/null @@ -1,435 +0,0 @@ -""" -.. _utils-htc-monitor: - -HTCondor Monitoring -------------------- - -A module with utility to query the HTCondor queue, process -the returned data and display it nicely. - -Note ----- - This module is meant to be called as a script, but some - of the individual functionality is made public API and - one shoule be able to build a different monitor script - from the functions in here. -""" -import re -import time - -import pendulum -from loguru import logger -from rich import box -from rich.console import Group -from rich.live import Live -from rich.panel import Panel -from rich.table import Table - -from pyhdtoolkit.models.htc import BaseSummary, ClusterSummary, HTCTaskSummary -from pyhdtoolkit.utils.cmdline import CommandLine -from pyhdtoolkit.utils.logging import config_logger - -config_logger(level="ERROR") - -# ----- Caching ------ # - -# We compile our regex pattern once only -_SCHEDD_RE: re.Pattern[str] = re.compile(r"Schedd:\s+([^.]+)\.cern\.ch") - -# ----- Settings ----- # - -TASK_COLUMNS_SETTINGS: dict[str, dict[str, str | bool]] = { - "OWNER": {"justify": "left", "header_style": "bold", "style": "bold", "no_wrap": True}, - "BATCH_NAME": {"justify": "center", "header_style": "magenta", "style": "magenta", "no_wrap": True}, - "SUBMITTED": { - "justify": "center", - "header_style": "medium_turquoise", - "style": "medium_turquoise", - "no_wrap": True, - }, - "DONE": {"justify": "right", "header_style": "bold green3", "style": "bold green3", "no_wrap": True}, - "RUNNING": { - "justify": "right", - "header_style": "bold cornflower_blue", - "style": "bold cornflower_blue", - "no_wrap": True, - }, - "IDLE": {"justify": "right", "header_style": "bold dark_orange3", "style": "bold dark_orange3", "no_wrap": True}, - "TOTAL": {"justify": "right", "style": "bold", "no_wrap": True}, - "JOB_IDS": {"justify": "right", "no_wrap": True}, -} - -CLUSTER_COLUMNS_SETTINGS: dict[str, dict[str, str | bool]] = { - "SOURCE": {"justify": "left", "header_style": "bold", "style": "bold", "no_wrap": True}, - "JOBS": {"justify": "right", "header_style": "bold", "style": "bold", "no_wrap": True}, - "COMPLETED": {"justify": "right", "header_style": "bold green3", "style": "bold green3", "no_wrap": True}, - "RUNNING": { - "justify": "right", - "header_style": "bold cornflower_blue", - "style": "bold cornflower_blue", - "no_wrap": True, - }, - "IDLE": {"justify": "right", "header_style": "bold dark_orange3", "style": "bold dark_orange3", "no_wrap": True}, - "HELD": {"justify": "right", "header_style": "bold gold1", "style": "bold gold1", "no_wrap": True}, - "SUSPENDED": {"justify": "right", "header_style": "bold slate_blue1", "style": "bold slate_blue1", "no_wrap": True}, - "REMOVED": {"justify": "right", "header_style": "bold red3", "style": "bold red3", "no_wrap": True}, -} - - -# ----- HTCondor Querying / Processing ----- # - - -def query_condor_q() -> str: - """ - .. versionadded:: 0.9.0 - - Returns a decoded string with the result of the - ``condor_q`` command, to get the status of the - caller' jobs. - - Returns - ------- - str - The utf-8 decoded string returned by the - ``condor_q`` command. - """ - return_code, raw_result = CommandLine.run("condor_q") - condor_status = raw_result.decode().strip() - if return_code == 0: - return condor_status - - # An issue occured, let's raise - msg = "Checking htcondor status failed" - raise ChildProcessError(msg) - - -def read_condor_q(report: str) -> tuple[list[HTCTaskSummary], ClusterSummary]: - """ - .. versionadded:: 0.9.0 - - Splits information from different parts of the ``condor_q`` - command's output into one clean, validated data structures. - - Parameters - ---------- - report : str - The utf-8 decoded string returned by the ``condor_q`` - command, as returned by `query_condor_q` . - - Returns - ------- - tuple[list[HTCTaskSummary], ClusterSummary] - A tuple with two elements. The first element is a list of - each task summary given by ``condor_q``, as a validated - `~.models.htc.HTCTaskSummary`. The second element is a - validated `~.models.htc.ClusterSummary` object with the - scheduler identification and summaries of the user as well - as all users' statistics on this scheduler cluster. - - Example - ------- - .. code-block:: python - - condor_q_output = get_the_string_as_you_wish(...) - tasks, cluster = read_condor_q(condor_q_output) - """ - tasks: list[HTCTaskSummary] = [] - next_line_is_task_report = False - - for line in report.splitlines(): - if line.startswith("-- Schedd:"): # extract scheduler information - scheduler_id = _process_scheduler_information_line(line) - - elif line.startswith("OWNER"): # headers line before we get task reports - next_line_is_task_report = True - - elif next_line_is_task_report: # extract task report information - if line not in ("\n", ""): - tasks.append(_process_task_summary_line(line)) - else: # an empty line denotes the end of the task report(s) - next_line_is_task_report = False - - else: # extract cluster information, only 3 lines here - querying_owner = tasks[0].owner if tasks else r"(\D+)" - if "query" in line: # first line - query_summary = _process_cluster_summary_line(line, "query") - elif "all users" in line: # last line - full_summary = _process_cluster_summary_line(line, "all users") - elif line not in ("\n", ""): # user line, whoever the user is - owner_summary = _process_cluster_summary_line(line, querying_owner) - cluster_summary = ClusterSummary( - scheduler_id=scheduler_id, query=query_summary, user=owner_summary, cluster=full_summary - ) - return tasks, cluster_summary - - -# ----- Output Formating ----- # - - -def _make_tasks_table(tasks: list[HTCTaskSummary]) -> Table: - """ - Takes the list of `~.models.htc.HTCTaskSummary` models - as returned by `read_condor_q` and from the information - within creates a `rich.table.Table`. Each row of the - table represents one `HTCTaskSummary` from the input. - The returned object is ready to be displayed by `rich`. - - Parameters - ---------- - tasks : list[HTCTaskSummary] - A list of `~.models.htc.HTCTaskSummary` models, as - parsed from the output of the ``condor_q`` command. - - Returns - ------- - rich.table.Table - A `rich.table.Table` object with the tasks information - formatted and ready to be displayed by `rich`. - """ - table = _default_tasks_table() - date_display_format = "dddd, D MMM YY at LT (zz)" # example: Wednesday, 21 Apr 21 9:04 PM (CEST) - for task in tasks: - table.add_row( - task.owner, - str(task.batch_name), - task.submitted.format(fmt=date_display_format), - str(task.done), - str(task.run), - str(task.idle), - str(task.total), - task.job_ids, - ) - return table - - -def _make_cluster_table(owner_name: str, cluster: ClusterSummary) -> Table: - """ - Takes a `~.models.htc.ClusterSummary` model as returned by - `read_condor_q` and from the information within creates a - `rich.table.Table`. The returned object is ready to be - displayed by `rich`. - - Parameters - ---------- - owner_name : str - The name of the user who queried the HTCondor queue. - cluster : ClusterSummary - A `~.models.htc.ClusterSummary` model, as parsed from - the output of the ``condor_q`` command. - - Returns - ------- - rich.table.Table - A `rich.table.Table` object with the cluster information - formatted and ready to be displayed by `rich`. - """ - table = _default_cluster_table() - for i, source in enumerate(["query", "user", "cluster"]): - table.add_row( - "Query" if i == 0 else ("All Users" if i == 2 else owner_name), # noqa: PLR2004 - str(cluster.model_dump()[source]["jobs"]), - str(cluster.model_dump()[source]["completed"]), - str(cluster.model_dump()[source]["running"]), - str(cluster.model_dump()[source]["idle"]), - str(cluster.model_dump()[source]["held"]), - str(cluster.model_dump()[source]["suspended"]), - str(cluster.model_dump()[source]["removed"]), - ) - return table - - -# ----- Helpers ----- # - - -def _process_scheduler_information_line(line: str) -> str: - """ - Extract only the 'Schedd: .cern.ch' part - of the scheduler information line. - - Parameters - ---------- - line : str - The line containing the scheduler information. - - Returns - ------- - str - The scheduler name extracted from the input line. - - Raises - ------ - ValueError - If the scheduler information could not be extracted - from the input line. This typically happens when no - jobs are present in the HTCondor queue and condor_q - returns empty lines. - """ - match: re.Match[str] | None = _SCHEDD_RE.search(line) - if match is None: - raise ValueError("Could not extract scheduler information from HTCondor output.") - return match.group(1) - - -def _process_task_summary_line(line: str) -> HTCTaskSummary: - """ - Extract the various information in a task summary line, - validated and returned as an `HTCTaskSummary` object. - - Parameters - ---------- - line : str - The line containing the task summary information. - - Returns - ------- - pyhdtoolkit.models.htc.HTCTaskSummary - The task summary information as a validated - `~.models.htc.HTCTaskSummary` object. - """ - line_elements = line.split() - return HTCTaskSummary( - owner=line_elements[0], - batch_name=line_elements[2], # line_elements[1] is the 'ID:' part, we don't need it - submitted=pendulum.from_format( - f"{line_elements[3]} {line_elements[4]}", fmt="MM/D HH:mm", tz="Europe/Paris" - ), # Geneva timezone is Paris timezone, - done=line_elements[5], - run=line_elements[6], - idle=line_elements[7], - total=line_elements[8], - job_ids=line_elements[9], - ) - - -def _process_cluster_summary_line(line: str, query: str | None = None) -> BaseSummary: - r""" - Extract the various information in a cluster summary line, - validated and returned as a `~.models.htc.BaseSummary`. - - Note - ---- - Beware if no jobs are running we can't have taken the - ``querying_owner`` info from tasks summaries, so we need - to match a wildcard word by giving querying_owner=(\D+). - This would add a match to the regex search, and we need - to look one match further for the wanted information. - - Parameters - ---------- - line : str - The line containing the cluster summary information. - query : str, optional - The name of the user who queried the HTCondor queue. - - Returns - ------- - pyhdtoolkit.models.htc.BaseSummary - The cluster summary information as a validated - `~.models.htc.BaseSummary` object. - """ - result = re.search( - rf"Total for {query}: (\d+) jobs; (\d+) completed, " - r"(\d+) removed, (\d+) idle, (\d+) running, (\d+) held, (\d+) suspended", - line, - ) - first_interesting_match_index = 1 if query != r"(\D+)" else 2 - return BaseSummary( - jobs=result.group(first_interesting_match_index), - completed=result.group(first_interesting_match_index + 1), - removed=result.group(first_interesting_match_index + 2), - idle=result.group(first_interesting_match_index + 3), - running=result.group(first_interesting_match_index + 4), - held=result.group(first_interesting_match_index + 5), - suspended=result.group(first_interesting_match_index + 6), - ) - - -def _default_tasks_table() -> Table: - """ - Create the default structure for the Tasks - Table, hard coded columns and no rows added. - - Returns - ------- - rich.table.Table - A `rich.table.Table` object with the - default structure for the Tasks Table. - """ - table = Table(width=120, box=box.SIMPLE_HEAVY) - for header, header_col_settings in TASK_COLUMNS_SETTINGS.items(): - table.add_column(header, **header_col_settings) - return table - - -def _default_cluster_table() -> Table: - """ - Create the default structure for the Cluster - Table, hard coded columns and no rows added. - - Returns - ------- - rich.table.Table - A `rich.table.Table` object with the - default structure for the Cluster Table. - """ - table = Table(width=120, box=box.HORIZONTALS) - for header, header_col_settings in CLUSTER_COLUMNS_SETTINGS.items(): - table.add_column(header, **header_col_settings) - return table - - -# ----- Executable ----- # - - -@logger.catch() -def main(): - def generate_renderable() -> Group: - """ - .. versionadded:: 0.9.0 - - Function called to update the live display, - fetches data from htcondor, does the processing - and returns a Group with both Panels. - - Returns - ------- - rich.console.Group - A `rich.console.Group` object with two - `rich.panel.Panel` objects inside, one - holding the tasks table and the other - holding the cluster information. - """ - condor_string = query_condor_q() - user_tasks, cluster_info = read_condor_q(condor_string) - owner = user_tasks[0].owner if user_tasks else "User" - - tasks_table = _make_tasks_table(user_tasks) - cluster_table = _make_cluster_table(owner, cluster_info) - return Group( - Panel( - tasks_table, - title=f"Scheduler: {cluster_info.scheduler_id}.cern.ch", - expand=False, - border_style="scope.border", - ), - Panel( - cluster_table, - title=f"{cluster_info.scheduler_id} Statistics", - expand=False, - border_style="scope.border", - ), - ) - - with Live(generate_renderable(), refresh_per_second=0.25) as live: - live.console.log("Querying HTCondor Queue - Refreshed Every 5 Minutes\n") - while True: - try: - live.update(generate_renderable()) - time.sleep(300) - except KeyboardInterrupt: - live.console.log("Exiting Program") - break - - -if __name__ == "__main__": - main() diff --git a/pyhdtoolkit/utils/htcondor.py b/pyhdtoolkit/utils/htcondor.py index 06effb6d..5f00828a 100644 --- a/pyhdtoolkit/utils/htcondor.py +++ b/pyhdtoolkit/utils/htcondor.py @@ -15,21 +15,13 @@ from the functions in here. """ import re -import time import pendulum -from loguru import logger from rich import box -from rich.console import Group -from rich.live import Live -from rich.panel import Panel from rich.table import Table from pyhdtoolkit.models.htc import BaseSummary, ClusterSummary, HTCTaskSummary from pyhdtoolkit.utils.cmdline import CommandLine -from pyhdtoolkit.utils.logging import config_logger - -config_logger(level="ERROR") # ----- Caching ------ # @@ -376,60 +368,3 @@ def _default_cluster_table() -> Table: for header, header_col_settings in CLUSTER_COLUMNS_SETTINGS.items(): table.add_column(header, **header_col_settings) return table - - -# ----- Executable ----- # - - -@logger.catch() -def main(): - def generate_renderable() -> Group: - """ - .. versionadded:: 0.9.0 - - Function called to update the live display, - fetches data from htcondor, does the processing - and returns a Group with both Panels. - - Returns - ------- - rich.console.Group - A `rich.console.Group` object with two - `rich.panel.Panel` objects inside, one - holding the tasks table and the other - holding the cluster information. - """ - condor_string = query_condor_q() - user_tasks, cluster_info = read_condor_q(condor_string) - owner = user_tasks[0].owner if user_tasks else "User" - - tasks_table = _make_tasks_table(user_tasks) - cluster_table = _make_cluster_table(owner, cluster_info) - return Group( - Panel( - tasks_table, - title=f"Scheduler: {cluster_info.scheduler_id}.cern.ch", - expand=False, - border_style="scope.border", - ), - Panel( - cluster_table, - title=f"{cluster_info.scheduler_id} Statistics", - expand=False, - border_style="scope.border", - ), - ) - - with Live(generate_renderable(), refresh_per_second=0.25) as live: - live.console.log("Querying HTCondor Queue - Refreshed Every 5 Minutes\n") - while True: - try: - live.update(generate_renderable()) - time.sleep(300) - except KeyboardInterrupt: - live.console.log("Exiting Program") - break - - -if __name__ == "__main__": - main() From cc40a4260be1a0fb7595d24d11aa7b5596eb97a8 Mon Sep 17 00:00:00 2001 From: Felix Soubelet Date: Thu, 8 Jan 2026 11:51:11 +0100 Subject: [PATCH 16/70] remove 3.10 and add 3.14 to matrices, move 3.13 to 3.14 where its the only one --- .github/workflows/coverage.yml | 2 +- .github/workflows/cron.yml | 2 +- .github/workflows/documentation.yml | 2 +- .github/workflows/publish.yml | 2 +- .github/workflows/tests.yml | 2 +- 5 files changed, 5 insertions(+), 5 deletions(-) diff --git a/.github/workflows/coverage.yml b/.github/workflows/coverage.yml index 60205041..fde35641 100644 --- a/.github/workflows/coverage.yml +++ b/.github/workflows/coverage.yml @@ -15,7 +15,7 @@ jobs: coverage: runs-on: ubuntu-latest env: - python-version: "3.13" + python-version: "3.14" steps: - uses: actions/checkout@v5 diff --git a/.github/workflows/cron.yml b/.github/workflows/cron.yml index bf8fef97..8c0626ec 100644 --- a/.github/workflows/cron.yml +++ b/.github/workflows/cron.yml @@ -17,7 +17,7 @@ jobs: matrix: os: [ubuntu-22.04, ubuntu-24.04, macos-latest, windows-latest] # We escape with quotes so it doesn't get interpreted as float (e.g. 3.10 -> 3.1 by GA's parser) - python-version: ["3.10", "3.11", "3.12", "3.13"] # add new versions when they are released + python-version: ["3.11", "3.12", "3.13", "3.14"] # add new versions when they are released fail-fast: false steps: diff --git a/.github/workflows/documentation.yml b/.github/workflows/documentation.yml index b93e193c..69a53ebc 100644 --- a/.github/workflows/documentation.yml +++ b/.github/workflows/documentation.yml @@ -15,7 +15,7 @@ jobs: documentation: runs-on: ubuntu-latest env: - python-version: "3.13" + python-version: "3.14" steps: - uses: actions/checkout@v5 diff --git a/.github/workflows/publish.yml b/.github/workflows/publish.yml index 7bac630e..4c153d23 100644 --- a/.github/workflows/publish.yml +++ b/.github/workflows/publish.yml @@ -13,7 +13,7 @@ jobs: deploy: runs-on: ubuntu-latest env: - python-version: "3.13" + python-version: "3.14" steps: diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index ff372667..6ada8aa0 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -17,7 +17,7 @@ jobs: matrix: os: [ubuntu-22.04, ubuntu-24.04, macos-latest, windows-latest] # We escape with quotes so it doesn't get interpreted as float (e.g. 3.10 -> 3.1 by GA's parser) - python-version: ["3.10", "3.11", "3.12", "3.13"] # add new versions when they are released + python-version: ["3.11", "3.12", "3.13", "3.14"] # add new versions when they are released fail-fast: false steps: From 880e8219fd477fe37fe8858abaeab5f628a0c067 Mon Sep 17 00:00:00 2001 From: Felix Soubelet Date: Thu, 8 Jan 2026 11:54:01 +0100 Subject: [PATCH 17/70] turns out llvmlite does not do 3.14 --- .github/workflows/coverage.yml | 2 +- .github/workflows/cron.yml | 2 +- .github/workflows/documentation.yml | 2 +- .github/workflows/publish.yml | 2 +- .github/workflows/tests.yml | 2 +- 5 files changed, 5 insertions(+), 5 deletions(-) diff --git a/.github/workflows/coverage.yml b/.github/workflows/coverage.yml index fde35641..60205041 100644 --- a/.github/workflows/coverage.yml +++ b/.github/workflows/coverage.yml @@ -15,7 +15,7 @@ jobs: coverage: runs-on: ubuntu-latest env: - python-version: "3.14" + python-version: "3.13" steps: - uses: actions/checkout@v5 diff --git a/.github/workflows/cron.yml b/.github/workflows/cron.yml index 8c0626ec..9e1d16e4 100644 --- a/.github/workflows/cron.yml +++ b/.github/workflows/cron.yml @@ -17,7 +17,7 @@ jobs: matrix: os: [ubuntu-22.04, ubuntu-24.04, macos-latest, windows-latest] # We escape with quotes so it doesn't get interpreted as float (e.g. 3.10 -> 3.1 by GA's parser) - python-version: ["3.11", "3.12", "3.13", "3.14"] # add new versions when they are released + python-version: ["3.11", "3.12", "3.13"] # add new versions when they are released fail-fast: false steps: diff --git a/.github/workflows/documentation.yml b/.github/workflows/documentation.yml index 69a53ebc..b93e193c 100644 --- a/.github/workflows/documentation.yml +++ b/.github/workflows/documentation.yml @@ -15,7 +15,7 @@ jobs: documentation: runs-on: ubuntu-latest env: - python-version: "3.14" + python-version: "3.13" steps: - uses: actions/checkout@v5 diff --git a/.github/workflows/publish.yml b/.github/workflows/publish.yml index 4c153d23..7bac630e 100644 --- a/.github/workflows/publish.yml +++ b/.github/workflows/publish.yml @@ -13,7 +13,7 @@ jobs: deploy: runs-on: ubuntu-latest env: - python-version: "3.14" + python-version: "3.13" steps: diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index 6ada8aa0..771f75ae 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -17,7 +17,7 @@ jobs: matrix: os: [ubuntu-22.04, ubuntu-24.04, macos-latest, windows-latest] # We escape with quotes so it doesn't get interpreted as float (e.g. 3.10 -> 3.1 by GA's parser) - python-version: ["3.11", "3.12", "3.13", "3.14"] # add new versions when they are released + python-version: ["3.11", "3.12", "3.13"] # add new versions when they are released fail-fast: false steps: From 153cfa96de0a7d1e60583aeb31dbf6064ebc4f2f Mon Sep 17 00:00:00 2001 From: Felix Soubelet Date: Thu, 8 Jan 2026 12:09:07 +0100 Subject: [PATCH 18/70] import from new name --- tests/test_utils.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/test_utils.py b/tests/test_utils.py index 0207c0ba..e92cf081 100644 --- a/tests/test_utils.py +++ b/tests/test_utils.py @@ -18,7 +18,7 @@ from pyhdtoolkit.utils import _misc, logging from pyhdtoolkit.utils.cmdline import CommandLine from pyhdtoolkit.utils.decorators import deprecated, maybe_jit -from pyhdtoolkit.utils.htc_monitor import ( +from pyhdtoolkit.utils.htcondor import ( ClusterSummary, HTCTaskSummary, _make_cluster_table, From 9f9320cc48991467969ebe70b7e2567d058801e4 Mon Sep 17 00:00:00 2001 From: Felix Soubelet Date: Thu, 8 Jan 2026 12:24:17 +0100 Subject: [PATCH 19/70] docstrings --- pyhdtoolkit/scripts/htc_monitor.py | 18 +++++++++++++++++- pyhdtoolkit/utils/htcondor.py | 17 ++++++----------- 2 files changed, 23 insertions(+), 12 deletions(-) diff --git a/pyhdtoolkit/scripts/htc_monitor.py b/pyhdtoolkit/scripts/htc_monitor.py index ea8a2bb4..10f856f7 100644 --- a/pyhdtoolkit/scripts/htc_monitor.py +++ b/pyhdtoolkit/scripts/htc_monitor.py @@ -1,3 +1,19 @@ +""" +.. _utils-htcondor: + +HTCondor Monitoring Utilities +----------------------------- + +A script to query the HTCondor queue and display +the status nicely with rich. + +Note +---- + This module is meant to be called as a script. Utility + functionality is provided in `pyhdtoolkit.utils.htcondor`. + Some of it is made public API and one should be able to + build a different monitor script from the functions there. +""" import time from loguru import logger @@ -5,7 +21,7 @@ from rich.live import Live from rich.panel import Panel -from pyhdtoolkit.utils.htc_monitor import _make_cluster_table, _make_tasks_table, query_condor_q, read_condor_q +from pyhdtoolkit.utils.htcondor import _make_cluster_table, _make_tasks_table, query_condor_q, read_condor_q from pyhdtoolkit.utils.logging import config_logger config_logger(level="ERROR") diff --git a/pyhdtoolkit/utils/htcondor.py b/pyhdtoolkit/utils/htcondor.py index 5f00828a..b007a23f 100644 --- a/pyhdtoolkit/utils/htcondor.py +++ b/pyhdtoolkit/utils/htcondor.py @@ -1,18 +1,13 @@ """ -.. _utils-htc-monitor: +.. _utils-htcondor: -HTCondor Monitoring -------------------- +HTCondor Monitoring Utilities +----------------------------- A module with utility to query the HTCondor queue, process -the returned data and display it nicely. - -Note ----- - This module is meant to be called as a script, but some - of the individual functionality is made public API and - one shoule be able to build a different monitor script - from the functions in here. +the returned data and display it nicely with rich. Only +the utility functions are included here, a callable script +is provided in `pyhdtoolkit.scripts.htc_monitor`. """ import re From 4a67b881f097f7b00ff443e122bea5e7cd5567a4 Mon Sep 17 00:00:00 2001 From: Felix Soubelet Date: Thu, 8 Jan 2026 12:48:42 +0100 Subject: [PATCH 20/70] extracted --- pyhdtoolkit/scripts/htc_monitor.py | 77 ++++++++++++++++-------------- 1 file changed, 42 insertions(+), 35 deletions(-) diff --git a/pyhdtoolkit/scripts/htc_monitor.py b/pyhdtoolkit/scripts/htc_monitor.py index 10f856f7..014529d5 100644 --- a/pyhdtoolkit/scripts/htc_monitor.py +++ b/pyhdtoolkit/scripts/htc_monitor.py @@ -26,45 +26,51 @@ config_logger(level="ERROR") -@logger.catch() -def main(): - def generate_renderable() -> Group: - """ - .. versionadded:: 0.9.0 +# ----- Bread and Butter ----- # + +def generate_renderable() -> Group: + """ + .. versionadded:: 0.9.0 - Function called to update the live display, - fetches data from htcondor, does the processing - and returns a Group with both Panels. + Function called to update the live display, + fetches data from htcondor via 'condor_q', + processes the response into tables and returns + a `rich.console.Group` with Panels for both + the tasks and cluster information. - Returns - ------- - rich.console.Group - A `rich.console.Group` object with two - `rich.panel.Panel` objects inside, one - holding the tasks table and the other - holding the cluster information. - """ - condor_string = query_condor_q() - user_tasks, cluster_info = read_condor_q(condor_string) - owner = user_tasks[0].owner if user_tasks else "User" + Returns + ------- + rich.console.Group + A `rich.console.Group` object with two + `rich.panel.Panel` objects inside, one + holding the tasks table and the other + holding the cluster information. + """ + condor_string = query_condor_q() + user_tasks, cluster_info = read_condor_q(condor_string) + owner = user_tasks[0].owner if user_tasks else "User" - tasks_table = _make_tasks_table(user_tasks) - cluster_table = _make_cluster_table(owner, cluster_info) - return Group( - Panel( - tasks_table, - title=f"Scheduler: {cluster_info.scheduler_id}.cern.ch", - expand=False, - border_style="scope.border", - ), - Panel( - cluster_table, - title=f"{cluster_info.scheduler_id} Statistics", - expand=False, - border_style="scope.border", - ), - ) + tasks_table = _make_tasks_table(user_tasks) + cluster_table = _make_cluster_table(owner, cluster_info) + return Group( + Panel( + tasks_table, + title=f"Scheduler: {cluster_info.scheduler_id}.cern.ch", + expand=False, + border_style="scope.border", + ), + Panel( + cluster_table, + title=f"{cluster_info.scheduler_id} Statistics", + expand=False, + border_style="scope.border", + ), + ) +# ----- Entrypoint ----- # + +@logger.catch() +def main(): with Live(generate_renderable(), refresh_per_second=0.25) as live: live.console.log("Querying HTCondor Queue - Refreshed Every 5 Minutes\n") while True: @@ -75,6 +81,7 @@ def generate_renderable() -> Group: live.console.log("Exiting Program") break +# ----- Script Mode ----- # if __name__ == "__main__": main() From be3c71e2c8b7a2901ef333dfe7e4036b1990a363 Mon Sep 17 00:00:00 2001 From: Felix Soubelet Date: Thu, 8 Jan 2026 12:53:12 +0100 Subject: [PATCH 21/70] ignore the entrypoint one --- pyproject.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pyproject.toml b/pyproject.toml index 5e8af067..da529dd9 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -136,7 +136,7 @@ source = ["pyhdtoolkit/"] ignore_errors = true omit = [ "pyhdtoolkit/cpymadtools/setup.py", - "pyhdtoolkit/utils/htc_monitor.py", + "pyhdtoolkit/scripts/htc_monitor.py", ] exclude_also = [ "if TYPE_CHECKING:", # do not count if TYPE_CHECKING block imports (ignored at runtime) for coverage From 56e603b8a2a59dfbebce7df1ea84403b2a79d0f7 Mon Sep 17 00:00:00 2001 From: Felix Soubelet Date: Thu, 8 Jan 2026 12:57:53 +0100 Subject: [PATCH 22/70] custom exception --- pyhdtoolkit/utils/htcondor.py | 16 ++++++++++++++-- 1 file changed, 14 insertions(+), 2 deletions(-) diff --git a/pyhdtoolkit/utils/htcondor.py b/pyhdtoolkit/utils/htcondor.py index b007a23f..d095229c 100644 --- a/pyhdtoolkit/utils/htcondor.py +++ b/pyhdtoolkit/utils/htcondor.py @@ -9,6 +9,7 @@ the utility functions are included here, a callable script is provided in `pyhdtoolkit.scripts.htc_monitor`. """ + import re import pendulum @@ -62,6 +63,16 @@ "REMOVED": {"justify": "right", "header_style": "bold red3", "style": "bold red3", "no_wrap": True}, } +# ----- Exceptions ----- # + + +class SchedulerInformationError(ValueError): + """Raised when scheduler information cannot be extracted.""" + + def __init__(self, line: str) -> None: + errmsg = f"Could not extract scheduler information from HTCondor output: {line!r}" + super().__init__(errmsg) + # ----- HTCondor Querying / Processing ----- # @@ -144,6 +155,7 @@ def read_condor_q(report: str) -> tuple[list[HTCTaskSummary], ClusterSummary]: full_summary = _process_cluster_summary_line(line, "all users") elif line not in ("\n", ""): # user line, whoever the user is owner_summary = _process_cluster_summary_line(line, querying_owner) + cluster_summary = ClusterSummary( scheduler_id=scheduler_id, query=query_summary, user=owner_summary, cluster=full_summary ) @@ -245,7 +257,7 @@ def _process_scheduler_information_line(line: str) -> str: Raises ------ - ValueError + SchedulerInformationError If the scheduler information could not be extracted from the input line. This typically happens when no jobs are present in the HTCondor queue and condor_q @@ -253,7 +265,7 @@ def _process_scheduler_information_line(line: str) -> str: """ match: re.Match[str] | None = _SCHEDD_RE.search(line) if match is None: - raise ValueError("Could not extract scheduler information from HTCondor output.") + raise SchedulerInformationError(line) return match.group(1) From 5c01ebf3c81b0dd2eb8f17e3ec8e56cc431d87b3 Mon Sep 17 00:00:00 2001 From: Felix Soubelet Date: Thu, 8 Jan 2026 13:01:51 +0100 Subject: [PATCH 23/70] info on expected types and proper conversion before calling model --- pyhdtoolkit/models/htc.py | 8 ++++---- pyhdtoolkit/utils/htcondor.py | 4 ++-- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/pyhdtoolkit/models/htc.py b/pyhdtoolkit/models/htc.py index 9b08967e..d44d5aef 100644 --- a/pyhdtoolkit/models/htc.py +++ b/pyhdtoolkit/models/htc.py @@ -55,10 +55,10 @@ class HTCTaskSummary(BaseModel): model_config = ConfigDict(arbitrary_types_allowed=True) owner: str - batch_name: int + batch_name: int # only keep the part after 'ID:' submitted: DateTime - done: int | str - run: int | str - idle: int | str + done: int | str # can be "-" if jobs in other state + run: int | str # can be "-" if jobs in other state + idle: int | str # can be "-" if jobs in other state total: int job_ids: str diff --git a/pyhdtoolkit/utils/htcondor.py b/pyhdtoolkit/utils/htcondor.py index d095229c..58c62828 100644 --- a/pyhdtoolkit/utils/htcondor.py +++ b/pyhdtoolkit/utils/htcondor.py @@ -288,14 +288,14 @@ def _process_task_summary_line(line: str) -> HTCTaskSummary: line_elements = line.split() return HTCTaskSummary( owner=line_elements[0], - batch_name=line_elements[2], # line_elements[1] is the 'ID:' part, we don't need it + batch_name=int(line_elements[2]), # line_elements[1] is the 'ID:' part, we don't need it submitted=pendulum.from_format( f"{line_elements[3]} {line_elements[4]}", fmt="MM/D HH:mm", tz="Europe/Paris" ), # Geneva timezone is Paris timezone, done=line_elements[5], run=line_elements[6], idle=line_elements[7], - total=line_elements[8], + total=int(line_elements[8]), job_ids=line_elements[9], ) From 2afcfb943c139fd9986dda3cb802b7b78d22d26a Mon Sep 17 00:00:00 2001 From: Felix Soubelet Date: Thu, 8 Jan 2026 13:03:35 +0100 Subject: [PATCH 24/70] ignore this too --- pyproject.toml | 1 + 1 file changed, 1 insertion(+) diff --git a/pyproject.toml b/pyproject.toml index da529dd9..e31ac604 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -136,6 +136,7 @@ source = ["pyhdtoolkit/"] ignore_errors = true omit = [ "pyhdtoolkit/cpymadtools/setup.py", + "pyhdtoolkit/utils/htcondor.py", "pyhdtoolkit/scripts/htc_monitor.py", ] exclude_also = [ From 2383ac260fef9872db360f53e93f6bb435977f6a Mon Sep 17 00:00:00 2001 From: Felix Soubelet Date: Thu, 8 Jan 2026 13:04:32 +0100 Subject: [PATCH 25/70] include utility module in init --- pyhdtoolkit/utils/__init__.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pyhdtoolkit/utils/__init__.py b/pyhdtoolkit/utils/__init__.py index 6e1cdc77..3e81c650 100644 --- a/pyhdtoolkit/utils/__init__.py +++ b/pyhdtoolkit/utils/__init__.py @@ -1,3 +1,3 @@ -from . import cmdline, contexts, decorators, logging # noqa: TID252 +from . import cmdline, contexts, decorators, htcondor, logging # noqa: TID252 -__all__ = ["cmdline", "contexts", "decorators", "logging"] +__all__ = ["cmdline", "contexts", "decorators", "htcondor", "logging"] From adeb603bbcf3b9b2863107f95fbe42f9b9b596c9 Mon Sep 17 00:00:00 2001 From: Felix Soubelet Date: Thu, 8 Jan 2026 13:09:48 +0100 Subject: [PATCH 26/70] new custom exception --- pyhdtoolkit/utils/htcondor.py | 16 ++++++++++++---- 1 file changed, 12 insertions(+), 4 deletions(-) diff --git a/pyhdtoolkit/utils/htcondor.py b/pyhdtoolkit/utils/htcondor.py index 58c62828..1ef2d0b6 100644 --- a/pyhdtoolkit/utils/htcondor.py +++ b/pyhdtoolkit/utils/htcondor.py @@ -66,14 +66,22 @@ # ----- Exceptions ----- # -class SchedulerInformationError(ValueError): - """Raised when scheduler information cannot be extracted.""" +class SchedulerInformationParseError(ValueError): + """Raised when scheduler information line cannot be parsed properly.""" def __init__(self, line: str) -> None: errmsg = f"Could not extract scheduler information from HTCondor output: {line!r}" super().__init__(errmsg) +class ClusterSummaryParseError(ValueError): + """Raised when cluster summary line cannot be parsed properly.""" + + def __init__(self, line: str) -> None: + errmsg = f"Could not extract cluster summary information from HTCondor output: {line!r}" + super().__init__(errmsg) + + # ----- HTCondor Querying / Processing ----- # @@ -265,7 +273,7 @@ def _process_scheduler_information_line(line: str) -> str: """ match: re.Match[str] | None = _SCHEDD_RE.search(line) if match is None: - raise SchedulerInformationError(line) + raise SchedulerInformationParseError(line) return match.group(1) @@ -326,7 +334,7 @@ def _process_cluster_summary_line(line: str, query: str | None = None) -> BaseSu The cluster summary information as a validated `~.models.htc.BaseSummary` object. """ - result = re.search( + result: re.Match[str] | None = re.search( rf"Total for {query}: (\d+) jobs; (\d+) completed, " r"(\d+) removed, (\d+) idle, (\d+) running, (\d+) held, (\d+) suspended", line, From e166ebdaa4c819f3b8264d456f79bd8e15ed3417 Mon Sep 17 00:00:00 2001 From: Felix Soubelet Date: Thu, 8 Jan 2026 13:11:32 +0100 Subject: [PATCH 27/70] module level regex template --- pyhdtoolkit/utils/htcondor.py | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-) diff --git a/pyhdtoolkit/utils/htcondor.py b/pyhdtoolkit/utils/htcondor.py index 1ef2d0b6..35cb07f4 100644 --- a/pyhdtoolkit/utils/htcondor.py +++ b/pyhdtoolkit/utils/htcondor.py @@ -21,9 +21,22 @@ # ----- Caching ------ # -# We compile our regex pattern once only +# We compile regex patterns once only _SCHEDD_RE: re.Pattern[str] = re.compile(r"Schedd:\s+([^.]+)\.cern\.ch") +# This one needs to be formatted with the +# querying owner before it can be compiled +_CLUSTER_SUMMARY_RE_TEMPLATE: str = ( + r"Total for {query}: " + r"(?P\d+) jobs; " + r"(?P\d+) completed, " + r"(?P\d+) removed, " + r"(?P\d+) idle, " + r"(?P\d+) running, " + r"(?P\d+) held, " + r"(?P\d+) suspended" +) + # ----- Settings ----- # TASK_COLUMNS_SETTINGS: dict[str, dict[str, str | bool]] = { From 1dda2cefebdf3b0a5a46856802486aa75a004006 Mon Sep 17 00:00:00 2001 From: Felix Soubelet Date: Thu, 8 Jan 2026 13:41:45 +0100 Subject: [PATCH 28/70] more robust cluster summary line parsing and calling block. Much detail added to documentation --- pyhdtoolkit/utils/htcondor.py | 62 ++++++++++++++++++++++------------- 1 file changed, 39 insertions(+), 23 deletions(-) diff --git a/pyhdtoolkit/utils/htcondor.py b/pyhdtoolkit/utils/htcondor.py index 35cb07f4..081f00ec 100644 --- a/pyhdtoolkit/utils/htcondor.py +++ b/pyhdtoolkit/utils/htcondor.py @@ -169,13 +169,16 @@ def read_condor_q(report: str) -> tuple[list[HTCTaskSummary], ClusterSummary]: next_line_is_task_report = False else: # extract cluster information, only 3 lines here - querying_owner = tasks[0].owner if tasks else r"(\D+)" + # Try to see if we get the owner from the tasks + querying_owner: str | None = tasks[0].owner if tasks else None if "query" in line: # first line - query_summary = _process_cluster_summary_line(line, "query") + query_summary: BaseSummary = _process_cluster_summary_line(line, "query") elif "all users" in line: # last line - full_summary = _process_cluster_summary_line(line, "all users") - elif line not in ("\n", ""): # user line, whoever the user is - owner_summary = _process_cluster_summary_line(line, querying_owner) + full_summary: BaseSummary = _process_cluster_summary_line(line, "all users") + elif line not in ("\n", ""): # user line, whoever the user is (e.g. me, fesoubel) + # If there were no tasks, we provide None and let the function default to + # a wildcard in the regex which will match anything up to the colon + owner_summary: BaseSummary = _process_cluster_summary_line(line, querying_owner) cluster_summary = ClusterSummary( scheduler_id=scheduler_id, query=query_summary, user=owner_summary, cluster=full_summary @@ -328,11 +331,20 @@ def _process_cluster_summary_line(line: str, query: str | None = None) -> BaseSu Note ---- - Beware if no jobs are running we can't have taken the - ``querying_owner`` info from tasks summaries, so we need - to match a wildcard word by giving querying_owner=(\D+). - This would add a match to the regex search, and we need - to look one match further for the wanted information. + A typical block to parse lines from looks like this: + + .. code-block:: bash + + Total for query: 63 jobs; 0 completed, 0 removed, 1 idle, 62 running, 0 held, 0 suspended + Total for fesoubel: 63 jobs; 0 completed, 0 removed, 1 idle, 62 running, 0 held, 0 suspended + Total for all users: 7279 jobs; 1 completed, 1 removed, 3351 idle, 3724 running, 202 held, 0 suspended + + Beware that if no jobs are running for the querying user (calling + 'condor_q') the calling function (read_condor_q) will not have been + able to determine the `owner` info from the tasks summaries. In this + case, the line for the user (i.e. fesoubel in the example above) will + need to be parsed with a wildcard instead of the actual user name. For + this we use r"[^:]+" which will match anything up to the colon. Parameters ---------- @@ -347,20 +359,24 @@ def _process_cluster_summary_line(line: str, query: str | None = None) -> BaseSu The cluster summary information as a validated `~.models.htc.BaseSummary` object. """ - result: re.Match[str] | None = re.search( - rf"Total for {query}: (\d+) jobs; (\d+) completed, " - r"(\d+) removed, (\d+) idle, (\d+) running, (\d+) held, (\d+) suspended", - line, - ) - first_interesting_match_index = 1 if query != r"(\D+)" else 2 + # We prepare the regex pattern with the proper query - if no query is given + # by caller (i.e. read_condor_q), we use a wildcard (see docstring note) + query_pattern: str = re.escape(query) if query is not None else r"[^:]+" + pattern: re.Pattern[str] = re.compile(_CLUSTER_SUMMARY_RE_TEMPLATE.format(query=query_pattern)) + + # Parse and search the line, exit early if no match + match: re.Match[str] | None = pattern.search(line) + if match is None: + raise ClusterSummaryParseError(line) + return BaseSummary( - jobs=result.group(first_interesting_match_index), - completed=result.group(first_interesting_match_index + 1), - removed=result.group(first_interesting_match_index + 2), - idle=result.group(first_interesting_match_index + 3), - running=result.group(first_interesting_match_index + 4), - held=result.group(first_interesting_match_index + 5), - suspended=result.group(first_interesting_match_index + 6), + jobs=int(match["jobs"]), + completed=int(match["completed"]), + removed=int(match["removed"]), + idle=int(match["idle"]), + running=int(match["running"]), + held=int(match["held"]), + suspended=int(match["suspended"]), ) From 696c8dfa2d15733bbc31008c8e35498198945641 Mon Sep 17 00:00:00 2001 From: Felix Soubelet Date: Thu, 8 Jan 2026 13:46:08 +0100 Subject: [PATCH 29/70] also use named groups for this regex --- pyhdtoolkit/utils/htcondor.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pyhdtoolkit/utils/htcondor.py b/pyhdtoolkit/utils/htcondor.py index 081f00ec..058288f8 100644 --- a/pyhdtoolkit/utils/htcondor.py +++ b/pyhdtoolkit/utils/htcondor.py @@ -22,7 +22,7 @@ # ----- Caching ------ # # We compile regex patterns once only -_SCHEDD_RE: re.Pattern[str] = re.compile(r"Schedd:\s+([^.]+)\.cern\.ch") +_SCHEDD_RE: re.Pattern[str] = re.compile(r"Schedd:\s+(?P[^.]+)\.cern\.ch") # This one needs to be formatted with the # querying owner before it can be compiled @@ -290,7 +290,7 @@ def _process_scheduler_information_line(line: str) -> str: match: re.Match[str] | None = _SCHEDD_RE.search(line) if match is None: raise SchedulerInformationParseError(line) - return match.group(1) + return match["cluster"] def _process_task_summary_line(line: str) -> HTCTaskSummary: From 8267de67ae4c92e11bf506cb5455e75b4be3b714 Mon Sep 17 00:00:00 2001 From: Felix Soubelet Date: Thu, 8 Jan 2026 13:47:25 +0100 Subject: [PATCH 30/70] ty happy --- pyhdtoolkit/utils/htcondor.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pyhdtoolkit/utils/htcondor.py b/pyhdtoolkit/utils/htcondor.py index 058288f8..c2c5d73b 100644 --- a/pyhdtoolkit/utils/htcondor.py +++ b/pyhdtoolkit/utils/htcondor.py @@ -393,7 +393,7 @@ def _default_tasks_table() -> Table: """ table = Table(width=120, box=box.SIMPLE_HEAVY) for header, header_col_settings in TASK_COLUMNS_SETTINGS.items(): - table.add_column(header, **header_col_settings) + table.add_column(header, **header_col_settings) # ty:ignore[invalid-argument-type] return table @@ -410,5 +410,5 @@ def _default_cluster_table() -> Table: """ table = Table(width=120, box=box.HORIZONTALS) for header, header_col_settings in CLUSTER_COLUMNS_SETTINGS.items(): - table.add_column(header, **header_col_settings) + table.add_column(header, **header_col_settings) # ty:ignore[invalid-argument-type] return table From b3b20265a02f0709e77c6ef670c2120973853f91 Mon Sep 17 00:00:00 2001 From: Felix Soubelet Date: Thu, 8 Jan 2026 13:50:07 +0100 Subject: [PATCH 31/70] some types and formatting here --- pyhdtoolkit/scripts/htc_monitor.py | 17 +++++++++++++---- 1 file changed, 13 insertions(+), 4 deletions(-) diff --git a/pyhdtoolkit/scripts/htc_monitor.py b/pyhdtoolkit/scripts/htc_monitor.py index 014529d5..c3aae5ec 100644 --- a/pyhdtoolkit/scripts/htc_monitor.py +++ b/pyhdtoolkit/scripts/htc_monitor.py @@ -14,7 +14,9 @@ Some of it is made public API and one should be able to build a different monitor script from the functions there. """ + import time +from typing import TYPE_CHECKING from loguru import logger from rich.console import Group @@ -24,10 +26,14 @@ from pyhdtoolkit.utils.htcondor import _make_cluster_table, _make_tasks_table, query_condor_q, read_condor_q from pyhdtoolkit.utils.logging import config_logger +if TYPE_CHECKING: + from rich.table import Table + config_logger(level="ERROR") # ----- Bread and Butter ----- # + def generate_renderable() -> Group: """ .. versionadded:: 0.9.0 @@ -46,12 +52,12 @@ def generate_renderable() -> Group: holding the tasks table and the other holding the cluster information. """ - condor_string = query_condor_q() + condor_string: str = query_condor_q() user_tasks, cluster_info = read_condor_q(condor_string) - owner = user_tasks[0].owner if user_tasks else "User" + owner: str = user_tasks[0].owner if user_tasks else "User" - tasks_table = _make_tasks_table(user_tasks) - cluster_table = _make_cluster_table(owner, cluster_info) + tasks_table: Table = _make_tasks_table(user_tasks) + cluster_table: Table = _make_cluster_table(owner, cluster_info) return Group( Panel( tasks_table, @@ -67,8 +73,10 @@ def generate_renderable() -> Group: ), ) + # ----- Entrypoint ----- # + @logger.catch() def main(): with Live(generate_renderable(), refresh_per_second=0.25) as live: @@ -81,6 +89,7 @@ def main(): live.console.log("Exiting Program") break + # ----- Script Mode ----- # if __name__ == "__main__": From 49a032b8c0ba697b1da0dfe1c68fc225601df16f Mon Sep 17 00:00:00 2001 From: Felix Soubelet Date: Thu, 8 Jan 2026 13:57:51 +0100 Subject: [PATCH 32/70] up minor version --- pyhdtoolkit/version.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pyhdtoolkit/version.py b/pyhdtoolkit/version.py index 7f6746be..e23c0a7f 100644 --- a/pyhdtoolkit/version.py +++ b/pyhdtoolkit/version.py @@ -2,7 +2,7 @@ import sys from pathlib import Path -VERSION = "1.7.0" +VERSION = "1.8.0" def version_info() -> str: From 0613fe527c6dbb82c11d78a843232a2f5450ec1c Mon Sep 17 00:00:00 2001 From: Felix Soubelet Date: Thu, 8 Jan 2026 14:05:57 +0100 Subject: [PATCH 33/70] add new release info to docs --- docs/release.rst | 8 ++++++++ docs/releases/v1.8.0.rst | 32 ++++++++++++++++++++++++++++++++ 2 files changed, 40 insertions(+) create mode 100644 docs/releases/v1.8.0.rst diff --git a/docs/release.rst b/docs/release.rst index 9a923a7b..e9d2af28 100644 --- a/docs/release.rst +++ b/docs/release.rst @@ -3,6 +3,14 @@ Release Notes The full list of releases can be found in the GitHub repository's `releases page `_. +Version 1.8.0 +------------- + +.. toctree:: + :maxdepth: 2 + + releases/v1.8.0 + Version 1.7.0 ------------- diff --git a/docs/releases/v1.8.0.rst b/docs/releases/v1.8.0.rst new file mode 100644 index 00000000..94b9aa4b --- /dev/null +++ b/docs/releases/v1.8.0.rst @@ -0,0 +1,32 @@ +.. _release_1.8.0: + +Release `1.8.0` brings some project maintenance and a complete refactor of the `HTCondor`-related utilities from the package. + +Removals +~~~~~~~~ + +* The `pyhdtoolkit.utils.htc_monitor` module has been removed, and its functionality split. + +Additions +~~~~~~~~~ + +* A new module, `pyhdtoolkit.utils.htcondor`, has been created to host all `HTCondor`-related utilities. The previous `htc_monitor` module's functionality has been moved here, with some improvements. +* A new command-line script, `htcondor-monitor`, has been added to provide an easy way to monitor `HTCondor` clusters from the terminal. It contains the entrypoint from the previous `pyhdtoolkit.utils.htc_monitor` module, adapted to the new module structure. +* The new script is declared as `htc-monitor` in the project metadata. It can be called simply as `htc-monitor` at the command line in an environment where `PyhDToolkit` is installed. + +Enhancements +~~~~~~~~~~~~ + +* The regex parsing in the `HTCondor` utilities has been made more robust. + +Documentation +~~~~~~~~~~~~~ + +* The documentation has been adapted to reflect the new module structure and command-line script. + +Maintenance +~~~~~~~~~~~ + +* Updated Continuous Integration workflows to switch to `uv`, speeding up CI runs. + +See `v1.8.0 release notes on GitHub `_ and the `full changes since v1.7.0 `_. From 0531b2bf9b42b86fcc6e3288b20c870f28997ef4 Mon Sep 17 00:00:00 2001 From: Felix Soubelet Date: Thu, 8 Jan 2026 14:07:28 +0100 Subject: [PATCH 34/70] fix module name in doc --- docs/api/utils.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/api/utils.rst b/docs/api/utils.rst index 7a875d10..cfa9e7f1 100644 --- a/docs/api/utils.rst +++ b/docs/api/utils.rst @@ -15,7 +15,7 @@ Utils :members: :noindex: -.. automodule:: pyhdtoolkit.utils.htc_monitor +.. automodule:: pyhdtoolkit.utils.htcondor :members: :noindex: From f535eba60578a5958a7efc33c00e418af3caecec Mon Sep 17 00:00:00 2001 From: Felix Soubelet Date: Thu, 8 Jan 2026 14:12:07 +0100 Subject: [PATCH 35/70] do not keep the same anchor --- pyhdtoolkit/scripts/htc_monitor.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pyhdtoolkit/scripts/htc_monitor.py b/pyhdtoolkit/scripts/htc_monitor.py index c3aae5ec..3d38000b 100644 --- a/pyhdtoolkit/scripts/htc_monitor.py +++ b/pyhdtoolkit/scripts/htc_monitor.py @@ -1,5 +1,5 @@ """ -.. _utils-htcondor: +.. _script-htcmonitor: HTCondor Monitoring Utilities ----------------------------- From e0e59626e21394fd7d3f0fd7f7046d9a6539f84c Mon Sep 17 00:00:00 2001 From: Felix Soubelet Date: Thu, 8 Jan 2026 14:13:33 +0100 Subject: [PATCH 36/70] no more misc --- docs/api/utils.rst | 4 ---- 1 file changed, 4 deletions(-) diff --git a/docs/api/utils.rst b/docs/api/utils.rst index cfa9e7f1..11178a73 100644 --- a/docs/api/utils.rst +++ b/docs/api/utils.rst @@ -22,7 +22,3 @@ Utils .. automodule:: pyhdtoolkit.utils.logging :members: :noindex: - -.. .. automodule:: pyhdtoolkit.utils._misc -.. :members: -.. :noindex: \ No newline at end of file From 1f064fe9e81bd1a72fea870b2280b4a297ac845d Mon Sep 17 00:00:00 2001 From: Felix Soubelet Date: Thu, 8 Jan 2026 14:15:21 +0100 Subject: [PATCH 37/70] get an anchor --- docs/api.rst | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/docs/api.rst b/docs/api.rst index 35af06b7..e175506a 100644 --- a/docs/api.rst +++ b/docs/api.rst @@ -1,8 +1,10 @@ +.. _api-top: + API Reference ============= .. toctree:: :maxdepth: 2 :glob: - + api/* \ No newline at end of file From 411e6ac0491807ff06ba8c7b47ec35354ea13391 Mon Sep 17 00:00:00 2001 From: Felix Soubelet Date: Thu, 8 Jan 2026 14:23:28 +0100 Subject: [PATCH 38/70] add scripts section to docs, include HTCondor monitor and skeleton for others --- docs/index.rst | 3 ++- docs/script/htc_monitor.rst | 8 ++++++++ docs/scripts.rst | 17 +++++++++++++++++ 3 files changed, 27 insertions(+), 1 deletion(-) create mode 100644 docs/script/htc_monitor.rst create mode 100644 docs/scripts.rst diff --git a/docs/index.rst b/docs/index.rst index 3921a1c9..604c650c 100644 --- a/docs/index.rst +++ b/docs/index.rst @@ -86,6 +86,7 @@ Contents quickstart gallery/index + scripts api contributing release @@ -121,7 +122,7 @@ The following people have contributed to the development of PyhDToolkit by contr License ------- -The package is licensed under the `MIT license `_. +The package is licensed under the `MIT license `_. Indices and tables ------------------ diff --git a/docs/script/htc_monitor.rst b/docs/script/htc_monitor.rst new file mode 100644 index 00000000..a9ece6d6 --- /dev/null +++ b/docs/script/htc_monitor.rst @@ -0,0 +1,8 @@ +.. _pyhdtoolkit-script-htcmonitor: + +HTCondor Monitor +================ + +.. automodule:: pyhdtoolkit.scripts.htc_monitor + :members: + :noindex: diff --git a/docs/scripts.rst b/docs/scripts.rst new file mode 100644 index 00000000..3d898ea8 --- /dev/null +++ b/docs/scripts.rst @@ -0,0 +1,17 @@ +.. _scripts-top: + +Command Line Scripts +==================== + +We provide a set of small command line utilities within `PyhDToolkit`. +Please note that scripts might require optional dependencies to be installed. + +Each script is registered in the project's metadata and will be callable from the command line with a simplified name after installing the package in your environment. +For more information on each script such as required extras, registered name, options and examples, please refer to their dedicated documentation page. +The following scripts are currently available: + +.. toctree:: + :maxdepth: 2 + :glob: + + script/* From caf151d4dd62f8066e64a0ed05e56c2c285a27ae Mon Sep 17 00:00:00 2001 From: Felix Soubelet Date: Thu, 8 Jan 2026 14:23:46 +0100 Subject: [PATCH 39/70] no double title --- pyhdtoolkit/scripts/htc_monitor.py | 3 --- 1 file changed, 3 deletions(-) diff --git a/pyhdtoolkit/scripts/htc_monitor.py b/pyhdtoolkit/scripts/htc_monitor.py index 3d38000b..51cd2d84 100644 --- a/pyhdtoolkit/scripts/htc_monitor.py +++ b/pyhdtoolkit/scripts/htc_monitor.py @@ -1,9 +1,6 @@ """ .. _script-htcmonitor: -HTCondor Monitoring Utilities ------------------------------ - A script to query the HTCondor queue and display the status nicely with rich. From 9efd5e4217b68fdcae04c07ece5bbeb7d2f72e53 Mon Sep 17 00:00:00 2001 From: Felix Soubelet Date: Thu, 8 Jan 2026 14:32:09 +0100 Subject: [PATCH 40/70] from future annotations --- docs/releases/v1.8.0.rst | 1 + pyhdtoolkit/cpymadtools/_generators.py | 2 ++ pyhdtoolkit/cpymadtools/constants.py | 2 ++ pyhdtoolkit/models/beam.py | 2 ++ pyhdtoolkit/models/htc.py | 8 +++++++- pyhdtoolkit/models/madx.py | 2 ++ pyhdtoolkit/optics/beam.py | 2 ++ pyhdtoolkit/optics/rdt.py | 2 ++ pyhdtoolkit/optics/twiss.py | 2 ++ pyhdtoolkit/scripts/htc_monitor.py | 2 ++ pyhdtoolkit/utils/htcondor.py | 2 ++ pyhdtoolkit/utils/logging.py | 2 ++ 12 files changed, 28 insertions(+), 1 deletion(-) diff --git a/docs/releases/v1.8.0.rst b/docs/releases/v1.8.0.rst index 94b9aa4b..5c873383 100644 --- a/docs/releases/v1.8.0.rst +++ b/docs/releases/v1.8.0.rst @@ -18,6 +18,7 @@ Enhancements ~~~~~~~~~~~~ * The regex parsing in the `HTCondor` utilities has been made more robust. +* The whole package now consistently makes use of postponed evaluations of annotations (see PEP 563). Documentation ~~~~~~~~~~~~~ diff --git a/pyhdtoolkit/cpymadtools/_generators.py b/pyhdtoolkit/cpymadtools/_generators.py index be8f8d1b..2411490c 100644 --- a/pyhdtoolkit/cpymadtools/_generators.py +++ b/pyhdtoolkit/cpymadtools/_generators.py @@ -10,6 +10,8 @@ gallery `. """ +from __future__ import annotations + # ----- Utlites ----- # diff --git a/pyhdtoolkit/cpymadtools/constants.py b/pyhdtoolkit/cpymadtools/constants.py index faa48d8b..96a53bb1 100644 --- a/pyhdtoolkit/cpymadtools/constants.py +++ b/pyhdtoolkit/cpymadtools/constants.py @@ -8,6 +8,8 @@ to help with consistency. """ +from __future__ import annotations + _MAX_SECTOR_VALUE: int = 8 # fmt: off diff --git a/pyhdtoolkit/models/beam.py b/pyhdtoolkit/models/beam.py index 5870800c..ffffa1be 100644 --- a/pyhdtoolkit/models/beam.py +++ b/pyhdtoolkit/models/beam.py @@ -8,6 +8,8 @@ data structures relative to particle beams. """ +from __future__ import annotations + from math import sqrt from pydantic import BaseModel diff --git a/pyhdtoolkit/models/htc.py b/pyhdtoolkit/models/htc.py index d44d5aef..74fdb708 100644 --- a/pyhdtoolkit/models/htc.py +++ b/pyhdtoolkit/models/htc.py @@ -8,9 +8,15 @@ data obtained by querying the ``HTCondor`` queue. """ -from pendulum import DateTime +from __future__ import annotations + +from typing import TYPE_CHECKING + from pydantic import BaseModel, ConfigDict +if TYPE_CHECKING: + from pendulum import DateTime + class BaseSummary(BaseModel): """ diff --git a/pyhdtoolkit/models/madx.py b/pyhdtoolkit/models/madx.py index a16de60c..d2f6ebfd 100644 --- a/pyhdtoolkit/models/madx.py +++ b/pyhdtoolkit/models/madx.py @@ -9,6 +9,8 @@ through `cpymad`. """ +from __future__ import annotations + from enum import Enum from pydantic import BaseModel, PositiveFloat, PositiveInt diff --git a/pyhdtoolkit/optics/beam.py b/pyhdtoolkit/optics/beam.py index 60948ed0..c27db5ef 100644 --- a/pyhdtoolkit/optics/beam.py +++ b/pyhdtoolkit/optics/beam.py @@ -8,6 +8,8 @@ simple beam parameter calculations. """ +from __future__ import annotations + import numpy as np from scipy import constants diff --git a/pyhdtoolkit/optics/rdt.py b/pyhdtoolkit/optics/rdt.py index 9b57ae87..9667e66d 100644 --- a/pyhdtoolkit/optics/rdt.py +++ b/pyhdtoolkit/optics/rdt.py @@ -8,6 +8,8 @@ resonance driving terms. """ +from __future__ import annotations + def rdt_to_order_and_type(rdt: int | str) -> str: """ diff --git a/pyhdtoolkit/optics/twiss.py b/pyhdtoolkit/optics/twiss.py index 93f8dce9..abb97f2a 100644 --- a/pyhdtoolkit/optics/twiss.py +++ b/pyhdtoolkit/optics/twiss.py @@ -7,6 +7,8 @@ Module implementing various calculations based on the ``TWISS`` optics parameters. """ +from __future__ import annotations + import numpy as np diff --git a/pyhdtoolkit/scripts/htc_monitor.py b/pyhdtoolkit/scripts/htc_monitor.py index 51cd2d84..9a569d7b 100644 --- a/pyhdtoolkit/scripts/htc_monitor.py +++ b/pyhdtoolkit/scripts/htc_monitor.py @@ -12,6 +12,8 @@ build a different monitor script from the functions there. """ +from __future__ import annotations + import time from typing import TYPE_CHECKING diff --git a/pyhdtoolkit/utils/htcondor.py b/pyhdtoolkit/utils/htcondor.py index c2c5d73b..8d67bd09 100644 --- a/pyhdtoolkit/utils/htcondor.py +++ b/pyhdtoolkit/utils/htcondor.py @@ -10,6 +10,8 @@ is provided in `pyhdtoolkit.scripts.htc_monitor`. """ +from __future__ import annotations + import re import pendulum diff --git a/pyhdtoolkit/utils/logging.py b/pyhdtoolkit/utils/logging.py index fb514a34..c2ed7f8d 100644 --- a/pyhdtoolkit/utils/logging.py +++ b/pyhdtoolkit/utils/logging.py @@ -17,6 +17,8 @@ - ``SIMPLE_FORMAT``: minimal, displays the local time, the level and the message. """ +from __future__ import annotations + import sys from loguru import logger From b190ce876538e7ee80c70c989780d107a144fc4e Mon Sep 17 00:00:00 2001 From: Felix Soubelet Date: Thu, 8 Jan 2026 14:41:26 +0100 Subject: [PATCH 41/70] with pydantiuc model rebuild --- pyhdtoolkit/models/htc.py | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/pyhdtoolkit/models/htc.py b/pyhdtoolkit/models/htc.py index 74fdb708..db461a8e 100644 --- a/pyhdtoolkit/models/htc.py +++ b/pyhdtoolkit/models/htc.py @@ -10,13 +10,12 @@ from __future__ import annotations -from typing import TYPE_CHECKING - +# Do not move DateTime import into a TYPE_CHECKING block, since +# we need it defined to rebuild the pydantic model for validation +# (this is required when using from __future__ import annotations) +from pendulum import DateTime # noqa: TC002 from pydantic import BaseModel, ConfigDict -if TYPE_CHECKING: - from pendulum import DateTime - class BaseSummary(BaseModel): """ @@ -68,3 +67,8 @@ class HTCTaskSummary(BaseModel): idle: int | str # can be "-" if jobs in other state total: int job_ids: str + + +# This is necessary to make pydantic recognize the DateTime type +# from pendulum when using from __future__ import annotations +HTCTaskSummary.model_rebuild() From cbab7f10b16de1f5980925bff08eaa8d8b972c9a Mon Sep 17 00:00:00 2001 From: Felix Soubelet Date: Thu, 8 Jan 2026 14:51:38 +0100 Subject: [PATCH 42/70] info for new functionality --- docs/releases/v1.8.0.rst | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/releases/v1.8.0.rst b/docs/releases/v1.8.0.rst index 5c873383..71d9579a 100644 --- a/docs/releases/v1.8.0.rst +++ b/docs/releases/v1.8.0.rst @@ -12,6 +12,7 @@ Additions * A new module, `pyhdtoolkit.utils.htcondor`, has been created to host all `HTCondor`-related utilities. The previous `htc_monitor` module's functionality has been moved here, with some improvements. * A new command-line script, `htcondor-monitor`, has been added to provide an easy way to monitor `HTCondor` clusters from the terminal. It contains the entrypoint from the previous `pyhdtoolkit.utils.htc_monitor` module, adapted to the new module structure. +* The new script allows passing command-line options to customize its behavior (see its documentation and help message for details). * The new script is declared as `htc-monitor` in the project metadata. It can be called simply as `htc-monitor` at the command line in an environment where `PyhDToolkit` is installed. Enhancements From 40b7710b213f27aef116e6ac792f258a8fbe2443 Mon Sep 17 00:00:00 2001 From: Felix Soubelet Date: Thu, 8 Jan 2026 14:51:53 +0100 Subject: [PATCH 43/70] declare typer as dependency for script --- pyproject.toml | 1 + uv.lock | 42 ++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 43 insertions(+) diff --git a/pyproject.toml b/pyproject.toml index e31ac604..551cc2cc 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -72,6 +72,7 @@ dependencies = [ [project.optional-dependencies] monitor = [ + "typer > 0.20", "rich >= 13.0", "pendulum >= 3.0", ] diff --git a/uv.lock b/uv.lock index 9e1f5af2..8120e975 100644 --- a/uv.lock +++ b/uv.lock @@ -148,6 +148,18 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/20/94/c5790835a017658cbfabd07f3bfb549140c3ac458cfc196323996b10095a/charset_normalizer-3.4.2-py3-none-any.whl", hash = "sha256:7f56930ab0abd1c45cd15be65cc741c28b1c9a34876ce8c17a2fa107810c0af0", size = 52626, upload-time = "2025-05-02T08:34:40.053Z" }, ] +[[package]] +name = "click" +version = "8.3.1" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "colorama", marker = "sys_platform == 'win32'" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/3d/fa/656b739db8587d7b5dfa22e22ed02566950fbfbcdc20311993483657a5c0/click-8.3.1.tar.gz", hash = "sha256:12ff4785d337a1bb490bb7e9c2b1ee5da3112e94a8622f26a6c77f5d2fc6842a", size = 295065, upload-time = "2025-11-15T20:45:42.706Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/98/78/01c019cdb5d6498122777c1a43056ebb3ebfeef2076d9d026bfe15583b2b/click-8.3.1-py3-none-any.whl", hash = "sha256:981153a64e25f12d547d3426c367a4857371575ee7ad18df2a6183ab0545b2a6", size = 108274, upload-time = "2025-11-15T20:45:41.139Z" }, +] + [[package]] name = "colorama" version = "0.4.6" @@ -1065,6 +1077,7 @@ all = [ { name = "sphinx-prompt" }, { name = "sphinx-rtd-theme" }, { name = "sphinxcontrib-bibtex" }, + { name = "typer" }, ] dev = [ { name = "ruff" }, @@ -1084,6 +1097,7 @@ docs = [ monitor = [ { name = "pendulum" }, { name = "rich" }, + { name = "typer" }, ] test = [ { name = "coverage", extra = ["toml"] }, @@ -1096,6 +1110,7 @@ test = [ { name = "pytest-randomly" }, { name = "pytest-xdist" }, { name = "rich" }, + { name = "typer" }, ] [package.metadata] @@ -1153,6 +1168,9 @@ requires-dist = [ { name = "sphinxcontrib-bibtex", marker = "extra == 'all'", specifier = ">=2.4" }, { name = "sphinxcontrib-bibtex", marker = "extra == 'docs'", specifier = ">=2.4" }, { name = "tfs-pandas", specifier = ">=3.8" }, + { name = "typer", marker = "extra == 'all'", specifier = ">0.20" }, + { name = "typer", marker = "extra == 'monitor'", specifier = ">0.20" }, + { name = "typer", marker = "extra == 'test'", specifier = ">0.20" }, ] provides-extras = ["all", "dev", "docs", "monitor", "test"] @@ -1410,6 +1428,15 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/a3/dc/17031897dae0efacfea57dfd3a82fdd2a2aeb58e0ff71b77b87e44edc772/setuptools-80.9.0-py3-none-any.whl", hash = "sha256:062d34222ad13e0cc312a4c02d73f059e86a4acbfbdea8f8f76b28c99f306922", size = 1201486, upload-time = "2025-05-27T00:56:49.664Z" }, ] +[[package]] +name = "shellingham" +version = "1.5.4" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/58/15/8b3609fd3830ef7b27b655beb4b4e9c62313a4e8da8c676e142cc210d58e/shellingham-1.5.4.tar.gz", hash = "sha256:8dbca0739d487e5bd35ab3ca4b36e11c4078f3a234bfce294b0a0291363404de", size = 10310, upload-time = "2023-10-24T04:13:40.426Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/e0/f9/0595336914c5619e5f28a1fb793285925a8cd4b432c9da0a987836c7f822/shellingham-1.5.4-py2.py3-none-any.whl", hash = "sha256:7ecfff8f2fd72616f7481040475a65b2bf8af90a56c89140852d1120324e8686", size = 9755, upload-time = "2023-10-24T04:13:38.866Z" }, +] + [[package]] name = "six" version = "1.17.0" @@ -1694,6 +1721,21 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/6e/c2/61d3e0f47e2b74ef40a68b9e6ad5984f6241a942f7cd3bbfbdbd03861ea9/tomli-2.2.1-py3-none-any.whl", hash = "sha256:cb55c73c5f4408779d0cf3eef9f762b9c9f147a77de7b258bef0a5628adc85cc", size = 14257, upload-time = "2024-11-27T22:38:35.385Z" }, ] +[[package]] +name = "typer" +version = "0.21.1" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "click" }, + { name = "rich" }, + { name = "shellingham" }, + { name = "typing-extensions" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/36/bf/8825b5929afd84d0dabd606c67cd57b8388cb3ec385f7ef19c5cc2202069/typer-0.21.1.tar.gz", hash = "sha256:ea835607cd752343b6b2b7ce676893e5a0324082268b48f27aa058bdb7d2145d", size = 110371, upload-time = "2026-01-06T11:21:10.989Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/a0/1d/d9257dd49ff2ca23ea5f132edf1281a0c4f9de8a762b9ae399b670a59235/typer-0.21.1-py3-none-any.whl", hash = "sha256:7985e89081c636b88d172c2ee0cfe33c253160994d47bdfdc302defd7d1f1d01", size = 47381, upload-time = "2026-01-06T11:21:09.824Z" }, +] + [[package]] name = "typing-extensions" version = "4.14.0" From ca370f49dd73990a9af32bed61c95cd653300af0 Mon Sep 17 00:00:00 2001 From: Felix Soubelet Date: Thu, 8 Jan 2026 14:58:43 +0100 Subject: [PATCH 44/70] logger.catch the generate_renderable, add CLI app from typer and first options --- pyhdtoolkit/scripts/htc_monitor.py | 27 +++++++++++++++++++++++---- 1 file changed, 23 insertions(+), 4 deletions(-) diff --git a/pyhdtoolkit/scripts/htc_monitor.py b/pyhdtoolkit/scripts/htc_monitor.py index 9a569d7b..3e38044f 100644 --- a/pyhdtoolkit/scripts/htc_monitor.py +++ b/pyhdtoolkit/scripts/htc_monitor.py @@ -10,6 +10,10 @@ functionality is provided in `pyhdtoolkit.utils.htcondor`. Some of it is made public API and one should be able to build a different monitor script from the functions there. + + + +TODO: document more this script. """ from __future__ import annotations @@ -17,6 +21,7 @@ import time from typing import TYPE_CHECKING +import typer from loguru import logger from rich.console import Group from rich.live import Live @@ -28,11 +33,15 @@ if TYPE_CHECKING: from rich.table import Table -config_logger(level="ERROR") + +# ----- CLI App ----- # + +app: typer.Typer = typer.Typer(help="A script to monitor HTCondor queue status.") # ----- Bread and Butter ----- # +@logger.catch() def generate_renderable() -> Group: """ .. versionadded:: 0.9.0 @@ -76,8 +85,18 @@ def generate_renderable() -> Group: # ----- Entrypoint ----- # -@logger.catch() -def main(): +@app.command() +def main( + log_level: str = typer.Option( + "ERROR", help="Console logging level. Can be 'DEBUG', 'INFO', 'WARNING' and 'ERROR'." + ), +): + """ + Parse the HTCondor queue and display + the status in a nice way using `rich`. + """ + config_logger(level=log_level) + with Live(generate_renderable(), refresh_per_second=0.25) as live: live.console.log("Querying HTCondor Queue - Refreshed Every 5 Minutes\n") while True: @@ -92,4 +111,4 @@ def main(): # ----- Script Mode ----- # if __name__ == "__main__": - main() + app() From feb26bedb4d4c040d84fa53b19d3520dd5018ad6 Mon Sep 17 00:00:00 2001 From: Felix Soubelet Date: Thu, 8 Jan 2026 15:11:58 +0100 Subject: [PATCH 45/70] need to declare the Typer app for script metadata --- pyproject.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pyproject.toml b/pyproject.toml index 551cc2cc..fee5ed24 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -111,7 +111,7 @@ all = [ ] [project.scripts] -htc-monitor = "pyhdtoolkit.scripts.htc_monitor:main" +htc-monitor = "pyhdtoolkit.scripts.htc_monitor:app" [project.urls] homepage = "https://github.com/fsoubelet/PyhDToolkit" From 2ab323c33a4d5bb75571bbee16df230a80b180ea Mon Sep 17 00:00:00 2001 From: Felix Soubelet Date: Thu, 8 Jan 2026 15:23:13 +0100 Subject: [PATCH 46/70] options --- pyhdtoolkit/scripts/htc_monitor.py | 17 ++++++++++------- 1 file changed, 10 insertions(+), 7 deletions(-) diff --git a/pyhdtoolkit/scripts/htc_monitor.py b/pyhdtoolkit/scripts/htc_monitor.py index 3e38044f..5ff0661c 100644 --- a/pyhdtoolkit/scripts/htc_monitor.py +++ b/pyhdtoolkit/scripts/htc_monitor.py @@ -21,11 +21,11 @@ import time from typing import TYPE_CHECKING -import typer from loguru import logger from rich.console import Group from rich.live import Live from rich.panel import Panel +from typer import Option, Typer from pyhdtoolkit.utils.htcondor import _make_cluster_table, _make_tasks_table, query_condor_q, read_condor_q from pyhdtoolkit.utils.logging import config_logger @@ -36,7 +36,7 @@ # ----- CLI App ----- # -app: typer.Typer = typer.Typer(help="A script to monitor HTCondor queue status.") +app: Typer = Typer(help="A script to monitor HTCondor queue status.") # ----- Bread and Butter ----- # @@ -87,22 +87,25 @@ def generate_renderable() -> Group: @app.command() def main( - log_level: str = typer.Option( - "ERROR", help="Console logging level. Can be 'DEBUG', 'INFO', 'WARNING' and 'ERROR'." - ), + wait: int = Option(300, "-w", "--wait", help="Seconds to wait between calls to `condor_q`."), + refresh: float = Option(0.25, "-r", "--refresh", help="Display refreshes per second (higher means more CPU usage)."), + log_level: str = Option("info", help="Console logging level. Can be 'DEBUG', 'INFO', 'WARNING' and 'ERROR'."), ): """ Parse the HTCondor queue and display the status in a nice way using `rich`. """ + # Configure our logger and level (only for functions, not rich Console) config_logger(level=log_level) - with Live(generate_renderable(), refresh_per_second=0.25) as live: + # Directly use Live to update the display. The display build itself + # is defined in the function above and takes care of the query etc. + with Live(generate_renderable(), refresh_per_second=refresh) as live: live.console.log("Querying HTCondor Queue - Refreshed Every 5 Minutes\n") while True: try: live.update(generate_renderable()) - time.sleep(300) + time.sleep(wait) except KeyboardInterrupt: live.console.log("Exiting Program") break From a108bea37b4851cb30e0f4ce7cee46e9f7272a9e Mon Sep 17 00:00:00 2001 From: Felix Soubelet Date: Thu, 8 Jan 2026 15:28:22 +0100 Subject: [PATCH 47/70] Specific error raised when condor_q fails us --- pyhdtoolkit/utils/htcondor.py | 16 ++++++++++++++-- 1 file changed, 14 insertions(+), 2 deletions(-) diff --git a/pyhdtoolkit/utils/htcondor.py b/pyhdtoolkit/utils/htcondor.py index 8d67bd09..69c9306c 100644 --- a/pyhdtoolkit/utils/htcondor.py +++ b/pyhdtoolkit/utils/htcondor.py @@ -97,6 +97,14 @@ def __init__(self, line: str) -> None: super().__init__(errmsg) +class CondorQError(ChildProcessError): + """Raised when executing the 'condor_q' command fails.""" + + def __init__(self) -> None: + errmsg = "Checking htcondor status (condor_q) failed" + super().__init__(errmsg) + + # ----- HTCondor Querying / Processing ----- # @@ -113,6 +121,11 @@ def query_condor_q() -> str: str The utf-8 decoded string returned by the ``condor_q`` command. + + Raises + ------ + CondorQError + If the ``condor_q`` command fails for any reason. """ return_code, raw_result = CommandLine.run("condor_q") condor_status = raw_result.decode().strip() @@ -120,8 +133,7 @@ def query_condor_q() -> str: return condor_status # An issue occured, let's raise - msg = "Checking htcondor status failed" - raise ChildProcessError(msg) + raise CondorQError() def read_condor_q(report: str) -> tuple[list[HTCTaskSummary], ClusterSummary]: From 24e60904bf8593dade5b557356cf39ebb7d83afa Mon Sep 17 00:00:00 2001 From: Felix Soubelet Date: Thu, 8 Jan 2026 15:36:45 +0100 Subject: [PATCH 48/70] no catching with logger, except more cases to handle --- pyhdtoolkit/scripts/htc_monitor.py | 31 +++++++++++++++++++++++------- 1 file changed, 24 insertions(+), 7 deletions(-) diff --git a/pyhdtoolkit/scripts/htc_monitor.py b/pyhdtoolkit/scripts/htc_monitor.py index 5ff0661c..198cba85 100644 --- a/pyhdtoolkit/scripts/htc_monitor.py +++ b/pyhdtoolkit/scripts/htc_monitor.py @@ -21,13 +21,20 @@ import time from typing import TYPE_CHECKING -from loguru import logger from rich.console import Group from rich.live import Live from rich.panel import Panel from typer import Option, Typer -from pyhdtoolkit.utils.htcondor import _make_cluster_table, _make_tasks_table, query_condor_q, read_condor_q +from pyhdtoolkit.utils.htcondor import ( + ClusterSummaryParseError, + CondorQError, + SchedulerInformationParseError, + _make_cluster_table, + _make_tasks_table, + query_condor_q, + read_condor_q, +) from pyhdtoolkit.utils.logging import config_logger if TYPE_CHECKING: @@ -41,7 +48,6 @@ # ----- Bread and Butter ----- # -@logger.catch() def generate_renderable() -> Group: """ .. versionadded:: 0.9.0 @@ -89,7 +95,7 @@ def generate_renderable() -> Group: def main( wait: int = Option(300, "-w", "--wait", help="Seconds to wait between calls to `condor_q`."), refresh: float = Option(0.25, "-r", "--refresh", help="Display refreshes per second (higher means more CPU usage)."), - log_level: str = Option("info", help="Console logging level. Can be 'DEBUG', 'INFO', 'WARNING' and 'ERROR'."), + log_level: str = Option("warning", help="Console logging level. Can be 'DEBUG', 'INFO', 'WARNING' and 'ERROR'."), ): """ Parse the HTCondor queue and display @@ -101,14 +107,25 @@ def main( # Directly use Live to update the display. The display build itself # is defined in the function above and takes care of the query etc. with Live(generate_renderable(), refresh_per_second=refresh) as live: - live.console.log("Querying HTCondor Queue - Refreshed Every 5 Minutes\n") + live.console.log(f"Querying HTCondor Queue - Refreshed Every {wait:d} Seconds\n") while True: - try: + try: # query HTCondor queue, process, update display live.update(generate_renderable()) time.sleep(wait) + # In case the 'condor_q' command failed + except CondorQError as err: + live.console.log(f"[red]Error querying HTCondor:[/red]\n {err}") + live.console.print_exception() + break # exits + # In case parsing the output of 'condor_q' failed + except (ClusterSummaryParseError, SchedulerInformationParseError) as err: + live.console.log(f"[red]Error parsing HTCondor output:[/red]\n {err}") + live.console.print_exception() + break # exits + # Allow user to exit cleanly except KeyboardInterrupt: live.console.log("Exiting Program") - break + break # exits # ----- Script Mode ----- # From 90da344d0c08b9322dac586bf912a7d529301bfc Mon Sep 17 00:00:00 2001 From: Felix Soubelet Date: Thu, 8 Jan 2026 15:46:54 +0100 Subject: [PATCH 49/70] little more info --- pyhdtoolkit/scripts/htc_monitor.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/pyhdtoolkit/scripts/htc_monitor.py b/pyhdtoolkit/scripts/htc_monitor.py index 198cba85..74242a25 100644 --- a/pyhdtoolkit/scripts/htc_monitor.py +++ b/pyhdtoolkit/scripts/htc_monitor.py @@ -107,7 +107,8 @@ def main( # Directly use Live to update the display. The display build itself # is defined in the function above and takes care of the query etc. with Live(generate_renderable(), refresh_per_second=refresh) as live: - live.console.log(f"Querying HTCondor Queue - Refreshed Every {wait:d} Seconds\n") + live.console.log(f"Querying HTCondor Queue - Every {wait:d} Seconds\n") + live.console.log(f"Display refresh rate: {refresh:.2f} per second") while True: try: # query HTCondor queue, process, update display live.update(generate_renderable()) From 8fab5c452889e4a1a88b636cf4552ebdc65b5507 Mon Sep 17 00:00:00 2001 From: Felix Soubelet Date: Thu, 8 Jan 2026 15:56:09 +0100 Subject: [PATCH 50/70] combine two console logs --- pyhdtoolkit/scripts/htc_monitor.py | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/pyhdtoolkit/scripts/htc_monitor.py b/pyhdtoolkit/scripts/htc_monitor.py index 74242a25..3d1cf671 100644 --- a/pyhdtoolkit/scripts/htc_monitor.py +++ b/pyhdtoolkit/scripts/htc_monitor.py @@ -94,7 +94,7 @@ def generate_renderable() -> Group: @app.command() def main( wait: int = Option(300, "-w", "--wait", help="Seconds to wait between calls to `condor_q`."), - refresh: float = Option(0.25, "-r", "--refresh", help="Display refreshes per second (higher means more CPU usage)."), + refresh: float = Option(0.25, "-r", "--refresh", help="Table display refreshes per second."), log_level: str = Option("warning", help="Console logging level. Can be 'DEBUG', 'INFO', 'WARNING' and 'ERROR'."), ): """ @@ -107,8 +107,7 @@ def main( # Directly use Live to update the display. The display build itself # is defined in the function above and takes care of the query etc. with Live(generate_renderable(), refresh_per_second=refresh) as live: - live.console.log(f"Querying HTCondor Queue - Every {wait:d} Seconds\n") - live.console.log(f"Display refresh rate: {refresh:.2f} per second") + live.console.log(f"Querying HTCondor every {wait:d} seconds (display refreshes {refresh:.2f} times/second).\n") while True: try: # query HTCondor queue, process, update display live.update(generate_renderable()) From 21c1563527655a9bd57801b3ab8fb3bd6d5200fb Mon Sep 17 00:00:00 2001 From: Felix Soubelet Date: Thu, 8 Jan 2026 16:06:30 +0100 Subject: [PATCH 51/70] attempt to have a progress bar for the waiting time --- pyhdtoolkit/scripts/htc_monitor.py | 57 ++++++++++++++++++++++++++---- 1 file changed, 50 insertions(+), 7 deletions(-) diff --git a/pyhdtoolkit/scripts/htc_monitor.py b/pyhdtoolkit/scripts/htc_monitor.py index 3d1cf671..9db2112b 100644 --- a/pyhdtoolkit/scripts/htc_monitor.py +++ b/pyhdtoolkit/scripts/htc_monitor.py @@ -21,9 +21,10 @@ import time from typing import TYPE_CHECKING -from rich.console import Group +from rich.console import Console, Group from rich.live import Live from rich.panel import Panel +from rich.progress import BarColumn, Progress, TextColumn, TimeRemainingColumn from typer import Option, Typer from pyhdtoolkit.utils.htcondor import ( @@ -38,6 +39,7 @@ from pyhdtoolkit.utils.logging import config_logger if TYPE_CHECKING: + from rich.progress import TaskID from rich.table import Table @@ -88,14 +90,43 @@ def generate_renderable() -> Group: ) +def wait_with_progress(console: Console, wait: int) -> None: + """ + Display a transient progress bar counting down to the next HTCondor query. + + Parameters + ---------- + console : Console + The `rich.console.Console` object to use for rendering. + wait : int + The number of seconds to wait for. + """ + refresh_interval = 0.1 # seconds + + with Progress( + TextColumn("Next HTCondor query"), + BarColumn(), + TimeRemainingColumn(), + console=console, + transient=True, + ) as progress: + task: TaskID = progress.add_task("waiting", total=wait) + + start: float = time.monotonic() + while not progress.finished: + elapsed: float = time.monotonic() - start + progress.update(task, completed=min(elapsed, wait)) + time.sleep(refresh_interval) + + # ----- Entrypoint ----- # @app.command() def main( - wait: int = Option(300, "-w", "--wait", help="Seconds to wait between calls to `condor_q`."), - refresh: float = Option(0.25, "-r", "--refresh", help="Table display refreshes per second."), - log_level: str = Option("warning", help="Console logging level. Can be 'DEBUG', 'INFO', 'WARNING' and 'ERROR'."), + wait: int = Option(300, "-w", "--wait", min=0, help="Seconds to wait between calls to `condor_q`."), + refresh: float = Option(1, "-r", "--refresh", min=0, help="Table display refreshes per second."), + log_level: str = Option("warning", help="Console logging level. Can be 'debug', 'info', 'warning' and 'error'."), ): """ Parse the HTCondor queue and display @@ -107,21 +138,33 @@ def main( # Directly use Live to update the display. The display build itself # is defined in the function above and takes care of the query etc. with Live(generate_renderable(), refresh_per_second=refresh) as live: - live.console.log(f"Querying HTCondor every {wait:d} seconds (display refreshes {refresh:.2f} times/second).\n") + # live.console.log(f"Querying HTCondor every {wait:d} seconds (display refreshes {refresh:.2f} times/second).\n") + live.console.log( + f"Querying HTCondor every {wait:d} seconds " + f"(display refreshes {refresh:.2f} times/second).\n" + ) + while True: - try: # query HTCondor queue, process, update display + try: + # query HTCondor queue, process, update display live.update(generate_renderable()) - time.sleep(wait) + + # Show countdown until next query + wait_with_progress(live.console, wait) + # time.sleep(wait) + # In case the 'condor_q' command failed except CondorQError as err: live.console.log(f"[red]Error querying HTCondor:[/red]\n {err}") live.console.print_exception() break # exits + # In case parsing the output of 'condor_q' failed except (ClusterSummaryParseError, SchedulerInformationParseError) as err: live.console.log(f"[red]Error parsing HTCondor output:[/red]\n {err}") live.console.print_exception() break # exits + # Allow user to exit cleanly except KeyboardInterrupt: live.console.log("Exiting Program") From cc27fbf97741c6a06cd7384c3d15d03d1f5bba6b Mon Sep 17 00:00:00 2001 From: Felix Soubelet Date: Thu, 8 Jan 2026 16:09:34 +0100 Subject: [PATCH 52/70] also min values --- pyhdtoolkit/scripts/htc_monitor.py | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/pyhdtoolkit/scripts/htc_monitor.py b/pyhdtoolkit/scripts/htc_monitor.py index 9db2112b..cfffa8a9 100644 --- a/pyhdtoolkit/scripts/htc_monitor.py +++ b/pyhdtoolkit/scripts/htc_monitor.py @@ -124,8 +124,8 @@ def wait_with_progress(console: Console, wait: int) -> None: @app.command() def main( - wait: int = Option(300, "-w", "--wait", min=0, help="Seconds to wait between calls to `condor_q`."), - refresh: float = Option(1, "-r", "--refresh", min=0, help="Table display refreshes per second."), + wait: int = Option(300, "-w", "--wait", min=1, help="Seconds to wait between calls to `condor_q`."), + refresh: float = Option(1, "-r", "--refresh", min=0.1, help="Table display refreshes per second."), log_level: str = Option("warning", help="Console logging level. Can be 'debug', 'info', 'warning' and 'error'."), ): """ @@ -139,10 +139,7 @@ def main( # is defined in the function above and takes care of the query etc. with Live(generate_renderable(), refresh_per_second=refresh) as live: # live.console.log(f"Querying HTCondor every {wait:d} seconds (display refreshes {refresh:.2f} times/second).\n") - live.console.log( - f"Querying HTCondor every {wait:d} seconds " - f"(display refreshes {refresh:.2f} times/second).\n" - ) + live.console.log(f"Querying HTCondor every {wait:d} seconds (display refreshes {refresh:.2f} times/second).\n") while True: try: From 2e01e57da673e98b4c335f4a09e601b80f33c897 Mon Sep 17 00:00:00 2001 From: Felix Soubelet Date: Thu, 8 Jan 2026 16:17:09 +0100 Subject: [PATCH 53/70] include progress bar --- docs/releases/v1.8.0.rst | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/releases/v1.8.0.rst b/docs/releases/v1.8.0.rst index 71d9579a..38060d14 100644 --- a/docs/releases/v1.8.0.rst +++ b/docs/releases/v1.8.0.rst @@ -13,6 +13,7 @@ Additions * A new module, `pyhdtoolkit.utils.htcondor`, has been created to host all `HTCondor`-related utilities. The previous `htc_monitor` module's functionality has been moved here, with some improvements. * A new command-line script, `htcondor-monitor`, has been added to provide an easy way to monitor `HTCondor` clusters from the terminal. It contains the entrypoint from the previous `pyhdtoolkit.utils.htc_monitor` module, adapted to the new module structure. * The new script allows passing command-line options to customize its behavior (see its documentation and help message for details). +* The new scripts provides a progress bar while waiting between `condor_q` calls. * The new script is declared as `htc-monitor` in the project metadata. It can be called simply as `htc-monitor` at the command line in an environment where `PyhDToolkit` is installed. Enhancements From 805c85d05135941465c7821f587f3daafcc0eae2 Mon Sep 17 00:00:00 2001 From: Felix Soubelet Date: Thu, 8 Jan 2026 16:17:19 +0100 Subject: [PATCH 54/70] progress bar above table layout maker --- pyhdtoolkit/scripts/htc_monitor.py | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/pyhdtoolkit/scripts/htc_monitor.py b/pyhdtoolkit/scripts/htc_monitor.py index cfffa8a9..5a6155d3 100644 --- a/pyhdtoolkit/scripts/htc_monitor.py +++ b/pyhdtoolkit/scripts/htc_monitor.py @@ -22,6 +22,7 @@ from typing import TYPE_CHECKING from rich.console import Console, Group +from rich.layout import Layout from rich.live import Live from rich.panel import Panel from rich.progress import BarColumn, Progress, TextColumn, TimeRemainingColumn @@ -119,6 +120,21 @@ def wait_with_progress(console: Console, wait: int) -> None: time.sleep(refresh_interval) +# ----- Progress + Layout helpers ----- # + + +def make_layout(progress: Progress, table_renderable) -> Layout: + """ + Create the main UI layout with the progress bar above the table. + """ + layout = Layout() + layout.split_column( + Layout(Panel(progress, title="Next HTCondor query", padding=(0, 1)), size=3), + Layout(table_renderable, ratio=1), + ) + return layout + + # ----- Entrypoint ----- # From 1c848240a8828bbc022ec09df4379710eb307fb0 Mon Sep 17 00:00:00 2001 From: Felix Soubelet Date: Thu, 8 Jan 2026 16:20:45 +0100 Subject: [PATCH 55/70] [WIP] reusable console and progress bar --- pyhdtoolkit/scripts/htc_monitor.py | 16 +++++++++++++--- 1 file changed, 13 insertions(+), 3 deletions(-) diff --git a/pyhdtoolkit/scripts/htc_monitor.py b/pyhdtoolkit/scripts/htc_monitor.py index 5a6155d3..71d7558a 100644 --- a/pyhdtoolkit/scripts/htc_monitor.py +++ b/pyhdtoolkit/scripts/htc_monitor.py @@ -151,10 +151,20 @@ def main( # Configure our logger and level (only for functions, not rich Console) config_logger(level=log_level) - # Directly use Live to update the display. The display build itself - # is defined in the function above and takes care of the query etc. + # Create re-usable console and progress bar + console: Console = Console() + progress: Progress = Progress( + TextColumn("Next HTCondor query"), + BarColumn(), + TimeRemainingColumn(), + console=console, + transient=True, + ) + task_id: TaskID = progress.add_task("waiting", total=wait) + + # Use an auto-updating live display. The display builds itself + # from the created layout we will pass to it. with Live(generate_renderable(), refresh_per_second=refresh) as live: - # live.console.log(f"Querying HTCondor every {wait:d} seconds (display refreshes {refresh:.2f} times/second).\n") live.console.log(f"Querying HTCondor every {wait:d} seconds (display refreshes {refresh:.2f} times/second).\n") while True: From ca8dddc63e0ccc371d239b0d1d3f28b58b218caf Mon Sep 17 00:00:00 2001 From: Felix Soubelet Date: Thu, 8 Jan 2026 16:23:38 +0100 Subject: [PATCH 56/70] [WIP] once per cycle tasks --- pyhdtoolkit/scripts/htc_monitor.py | 21 ++++++++++++++------- 1 file changed, 14 insertions(+), 7 deletions(-) diff --git a/pyhdtoolkit/scripts/htc_monitor.py b/pyhdtoolkit/scripts/htc_monitor.py index 71d7558a..5b308105 100644 --- a/pyhdtoolkit/scripts/htc_monitor.py +++ b/pyhdtoolkit/scripts/htc_monitor.py @@ -164,17 +164,24 @@ def main( # Use an auto-updating live display. The display builds itself # from the created layout we will pass to it. - with Live(generate_renderable(), refresh_per_second=refresh) as live: - live.console.log(f"Querying HTCondor every {wait:d} seconds (display refreshes {refresh:.2f} times/second).\n") + with Live(console=console, refresh_per_second=refresh) as live: + console.log( + f"Querying HTCondor queue every {wait:d} seconds " + f"(table display refreshes {refresh:.2f} times/second).\n" + ) + # live.console.log(f"Querying HTCondor every {wait:d} seconds (display refreshes {refresh:.2f} times/second).\n") while True: try: - # query HTCondor queue, process, update display - live.update(generate_renderable()) + # Once per cycle, query HTCondor the process its output + # and generate the table to be displayed + table: Group = generate_renderable() - # Show countdown until next query - wait_with_progress(live.console, wait) - # time.sleep(wait) + # Reset the progress bar (we just queried HTCondor) + progress.reset(task_id) + progress.update(task_id, total=wait, completed=0) + + # We start rendering # In case the 'condor_q' command failed except CondorQError as err: From 6cf9ed7aea99c64338bf45a29b816e21f5e65629 Mon Sep 17 00:00:00 2001 From: Felix Soubelet Date: Thu, 8 Jan 2026 16:26:24 +0100 Subject: [PATCH 57/70] [WIP] progress bar updates and re rendering --- pyhdtoolkit/scripts/htc_monitor.py | 16 +++++++++++++++- 1 file changed, 15 insertions(+), 1 deletion(-) diff --git a/pyhdtoolkit/scripts/htc_monitor.py b/pyhdtoolkit/scripts/htc_monitor.py index 5b308105..9cc00347 100644 --- a/pyhdtoolkit/scripts/htc_monitor.py +++ b/pyhdtoolkit/scripts/htc_monitor.py @@ -181,7 +181,21 @@ def main( progress.reset(task_id) progress.update(task_id, total=wait, completed=0) - # We start rendering + # We start rendering our layout with progress + table + live.update(make_layout(progress, table)) + + # Now we need to update the progress bar until we have + # waited long enough for the next query + start: float = time.monotonic() + while not progress.finished: + elapsed: float = time.monotonic() - start + progress.update(task_id, completed=min(elapsed, wait)) + + # Refresh the live display for the progress bar + live.update(make_layout(progress, table)) + + # And sleep a little + time.sleep(refresh) # In case the 'condor_q' command failed except CondorQError as err: From 0fb4af1f23af6e84c807eebdd35d53a2dbcf069e Mon Sep 17 00:00:00 2001 From: Felix Soubelet Date: Thu, 8 Jan 2026 16:26:50 +0100 Subject: [PATCH 58/70] formnatting --- pyhdtoolkit/scripts/htc_monitor.py | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/pyhdtoolkit/scripts/htc_monitor.py b/pyhdtoolkit/scripts/htc_monitor.py index 9cc00347..4f9cf480 100644 --- a/pyhdtoolkit/scripts/htc_monitor.py +++ b/pyhdtoolkit/scripts/htc_monitor.py @@ -166,10 +166,8 @@ def main( # from the created layout we will pass to it. with Live(console=console, refresh_per_second=refresh) as live: console.log( - f"Querying HTCondor queue every {wait:d} seconds " - f"(table display refreshes {refresh:.2f} times/second).\n" + f"Querying HTCondor queue every {wait:d} seconds (table display refreshes {refresh:.2f} times/second).\n" ) - # live.console.log(f"Querying HTCondor every {wait:d} seconds (display refreshes {refresh:.2f} times/second).\n") while True: try: From f32bf824519ecc33abef58a30eb7a4fc288b6c6c Mon Sep 17 00:00:00 2001 From: Felix Soubelet Date: Thu, 8 Jan 2026 16:37:27 +0100 Subject: [PATCH 59/70] [WIP] adapt sleep interval, dont recreate the layout so much --- pyhdtoolkit/scripts/htc_monitor.py | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/pyhdtoolkit/scripts/htc_monitor.py b/pyhdtoolkit/scripts/htc_monitor.py index 4f9cf480..596ac66c 100644 --- a/pyhdtoolkit/scripts/htc_monitor.py +++ b/pyhdtoolkit/scripts/htc_monitor.py @@ -150,15 +150,15 @@ def main( """ # Configure our logger and level (only for functions, not rich Console) config_logger(level=log_level) + sleep_interval = float(min(0.1, 1 / refresh)) # Create re-usable console and progress bar console: Console = Console() progress: Progress = Progress( - TextColumn("Next HTCondor query"), + TextColumn("[bold]Next HTCondor query[/bold]"), BarColumn(), TimeRemainingColumn(), console=console, - transient=True, ) task_id: TaskID = progress.add_task("waiting", total=wait) @@ -180,7 +180,8 @@ def main( progress.update(task_id, total=wait, completed=0) # We start rendering our layout with progress + table - live.update(make_layout(progress, table)) + layout: Layout = make_layout(progress, table) + live.update(layout) # Now we need to update the progress bar until we have # waited long enough for the next query @@ -190,10 +191,14 @@ def main( progress.update(task_id, completed=min(elapsed, wait)) # Refresh the live display for the progress bar - live.update(make_layout(progress, table)) + live.refresh() # And sleep a little - time.sleep(refresh) + time.sleep(sleep_interval) + + # This is to force a clean 100% completion render before resetting + progress.update(task_id, completed=wait) + live.refresh() # In case the 'condor_q' command failed except CondorQError as err: From a9d73aafea3b38185d007b14054842a3f2092594 Mon Sep 17 00:00:00 2001 From: Felix Soubelet Date: Thu, 8 Jan 2026 16:46:16 +0100 Subject: [PATCH 60/70] [wIP] should be max --- pyhdtoolkit/scripts/htc_monitor.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pyhdtoolkit/scripts/htc_monitor.py b/pyhdtoolkit/scripts/htc_monitor.py index 596ac66c..d06b5f57 100644 --- a/pyhdtoolkit/scripts/htc_monitor.py +++ b/pyhdtoolkit/scripts/htc_monitor.py @@ -150,7 +150,7 @@ def main( """ # Configure our logger and level (only for functions, not rich Console) config_logger(level=log_level) - sleep_interval = float(min(0.1, 1 / refresh)) + sleep_interval = float(max(0.1, 1 / refresh)) # Create re-usable console and progress bar console: Console = Console() From feb8ca9d9ab730bc15e9713570fbfe7eb24ddf5f Mon Sep 17 00:00:00 2001 From: Felix Soubelet Date: Thu, 8 Jan 2026 16:51:23 +0100 Subject: [PATCH 61/70] [wIP] taking the table width maybe --- pyhdtoolkit/scripts/htc_monitor.py | 19 +++++++++++++------ 1 file changed, 13 insertions(+), 6 deletions(-) diff --git a/pyhdtoolkit/scripts/htc_monitor.py b/pyhdtoolkit/scripts/htc_monitor.py index d06b5f57..4db57ed3 100644 --- a/pyhdtoolkit/scripts/htc_monitor.py +++ b/pyhdtoolkit/scripts/htc_monitor.py @@ -123,14 +123,21 @@ def wait_with_progress(console: Console, wait: int) -> None: # ----- Progress + Layout helpers ----- # -def make_layout(progress: Progress, table_renderable) -> Layout: +def make_layout(progress: Progress, tables: Group) -> Layout: """ - Create the main UI layout with the progress bar above the table. + Create the main UI layout with the progress bar above the table, + matching to the table width dynamically. """ + # Compute max width among all panels in the Group + table_width = max( + getattr(panel.renderable, "width", 0) + 2 # +2 for panel padding/borders + for panel in tables.renderables + ) + layout = Layout() layout.split_column( - Layout(Panel(progress, title="Next HTCondor query", padding=(0, 1)), size=3), - Layout(table_renderable, ratio=1), + Layout(Panel(progress, title="Next HTCondor query", padding=(0, 1), width=table_width)), + Layout(tables, ratio=1), ) return layout @@ -173,14 +180,14 @@ def main( try: # Once per cycle, query HTCondor the process its output # and generate the table to be displayed - table: Group = generate_renderable() + tables: Group = generate_renderable() # Reset the progress bar (we just queried HTCondor) progress.reset(task_id) progress.update(task_id, total=wait, completed=0) # We start rendering our layout with progress + table - layout: Layout = make_layout(progress, table) + layout: Layout = make_layout(progress, tables) live.update(layout) # Now we need to update the progress bar until we have From 5e6cce87bcbdc20eb50d4fa4edba2fc55b204f7e Mon Sep 17 00:00:00 2001 From: Felix Soubelet Date: Thu, 8 Jan 2026 16:57:45 +0100 Subject: [PATCH 62/70] [WIP] new make layout takes the console too --- pyhdtoolkit/scripts/htc_monitor.py | 23 ++++++++++++++++++----- 1 file changed, 18 insertions(+), 5 deletions(-) diff --git a/pyhdtoolkit/scripts/htc_monitor.py b/pyhdtoolkit/scripts/htc_monitor.py index 4db57ed3..c1c84581 100644 --- a/pyhdtoolkit/scripts/htc_monitor.py +++ b/pyhdtoolkit/scripts/htc_monitor.py @@ -123,20 +123,33 @@ def wait_with_progress(console: Console, wait: int) -> None: # ----- Progress + Layout helpers ----- # -def make_layout(progress: Progress, tables: Group) -> Layout: +def make_layout(progress: Progress, tables: Group, console: Console) -> Layout: """ Create the main UI layout with the progress bar above the table, - matching to the table width dynamically. + dynamically matching the table width (or console width if resized). + + Parameters + ---------- + progress : Progress + The Rich Progress instance for the countdown. + table_renderable : Group + The Group containing the task and cluster panels. + console : Console + The console, used for width fallback. """ # Compute max width among all panels in the Group - table_width = max( - getattr(panel.renderable, "width", 0) + 2 # +2 for panel padding/borders + table_width: int = max( # we add +2 for panel padding/borders + getattr(panel.renderable, "width", 0) + 2 # ty:ignore[unresolved-attribute] for panel in tables.renderables ) + # Ensure the panel doesn't exceed the console width + panel_width: int = min(table_width, console.width - 2) + + layout = Layout() layout.split_column( - Layout(Panel(progress, title="Next HTCondor query", padding=(0, 1), width=table_width)), + Layout(Panel(progress, title="time to Next HTCondor Query", padding=(0, 1), width=panel_width), size=3), Layout(tables, ratio=1), ) return layout From acce2ca4e043b8cb559977c81f8c5af75e8f5ac8 Mon Sep 17 00:00:00 2001 From: Felix Soubelet Date: Thu, 8 Jan 2026 16:58:31 +0100 Subject: [PATCH 63/70] [WIP] renaming --- pyhdtoolkit/scripts/htc_monitor.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pyhdtoolkit/scripts/htc_monitor.py b/pyhdtoolkit/scripts/htc_monitor.py index c1c84581..9e4df8c6 100644 --- a/pyhdtoolkit/scripts/htc_monitor.py +++ b/pyhdtoolkit/scripts/htc_monitor.py @@ -51,7 +51,7 @@ # ----- Bread and Butter ----- # -def generate_renderable() -> Group: +def generate_tables_renderable() -> Group: """ .. versionadded:: 0.9.0 @@ -193,7 +193,7 @@ def main( try: # Once per cycle, query HTCondor the process its output # and generate the table to be displayed - tables: Group = generate_renderable() + tables: Group = generate_tables_renderable() # Reset the progress bar (we just queried HTCondor) progress.reset(task_id) From 6f59f9ea4822c9e429ecad81f808c331fbf5b521 Mon Sep 17 00:00:00 2001 From: Felix Soubelet Date: Thu, 8 Jan 2026 16:59:39 +0100 Subject: [PATCH 64/70] [WIP] adapt call here --- pyhdtoolkit/scripts/htc_monitor.py | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/pyhdtoolkit/scripts/htc_monitor.py b/pyhdtoolkit/scripts/htc_monitor.py index 9e4df8c6..5227cee8 100644 --- a/pyhdtoolkit/scripts/htc_monitor.py +++ b/pyhdtoolkit/scripts/htc_monitor.py @@ -200,20 +200,18 @@ def main( progress.update(task_id, total=wait, completed=0) # We start rendering our layout with progress + table - layout: Layout = make_layout(progress, tables) + layout: Layout = make_layout(progress, tables, console) live.update(layout) - # Now we need to update the progress bar until we have - # waited long enough for the next query + # Now we need to update the progress bar until + # we have waited long enough for the next query start: float = time.monotonic() while not progress.finished: elapsed: float = time.monotonic() - start progress.update(task_id, completed=min(elapsed, wait)) - # Refresh the live display for the progress bar + # Refresh the live display for the progress bar and sleep live.refresh() - - # And sleep a little time.sleep(sleep_interval) # This is to force a clean 100% completion render before resetting From 71ad4ac92691967779154702b8d922a863129f13 Mon Sep 17 00:00:00 2001 From: Felix Soubelet Date: Thu, 8 Jan 2026 17:04:37 +0100 Subject: [PATCH 65/70] [WIP] remove unused code --- pyhdtoolkit/scripts/htc_monitor.py | 30 ------------------------------ 1 file changed, 30 deletions(-) diff --git a/pyhdtoolkit/scripts/htc_monitor.py b/pyhdtoolkit/scripts/htc_monitor.py index 5227cee8..bd46350b 100644 --- a/pyhdtoolkit/scripts/htc_monitor.py +++ b/pyhdtoolkit/scripts/htc_monitor.py @@ -91,35 +91,6 @@ def generate_tables_renderable() -> Group: ) -def wait_with_progress(console: Console, wait: int) -> None: - """ - Display a transient progress bar counting down to the next HTCondor query. - - Parameters - ---------- - console : Console - The `rich.console.Console` object to use for rendering. - wait : int - The number of seconds to wait for. - """ - refresh_interval = 0.1 # seconds - - with Progress( - TextColumn("Next HTCondor query"), - BarColumn(), - TimeRemainingColumn(), - console=console, - transient=True, - ) as progress: - task: TaskID = progress.add_task("waiting", total=wait) - - start: float = time.monotonic() - while not progress.finished: - elapsed: float = time.monotonic() - start - progress.update(task, completed=min(elapsed, wait)) - time.sleep(refresh_interval) - - # ----- Progress + Layout helpers ----- # @@ -146,7 +117,6 @@ def make_layout(progress: Progress, tables: Group, console: Console) -> Layout: # Ensure the panel doesn't exceed the console width panel_width: int = min(table_width, console.width - 2) - layout = Layout() layout.split_column( Layout(Panel(progress, title="time to Next HTCondor Query", padding=(0, 1), width=panel_width), size=3), From 8769a035dfd7e2ed36c65ac7199435007eb4adc9 Mon Sep 17 00:00:00 2001 From: Felix Soubelet Date: Thu, 8 Jan 2026 17:09:22 +0100 Subject: [PATCH 66/70] [WIP] use rich.measure.Measurement --- pyhdtoolkit/scripts/htc_monitor.py | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/pyhdtoolkit/scripts/htc_monitor.py b/pyhdtoolkit/scripts/htc_monitor.py index bd46350b..b6cd7926 100644 --- a/pyhdtoolkit/scripts/htc_monitor.py +++ b/pyhdtoolkit/scripts/htc_monitor.py @@ -24,6 +24,7 @@ from rich.console import Console, Group from rich.layout import Layout from rich.live import Live +from rich.measure import Measurement from rich.panel import Panel from rich.progress import BarColumn, Progress, TextColumn, TimeRemainingColumn from typer import Option, Typer @@ -110,12 +111,12 @@ def make_layout(progress: Progress, tables: Group, console: Console) -> Layout: """ # Compute max width among all panels in the Group table_width: int = max( # we add +2 for panel padding/borders - getattr(panel.renderable, "width", 0) + 2 # ty:ignore[unresolved-attribute] + Measurement.get(console, console.options, panel.renderable).maximum # ty:ignore[unresolved-attribute] for panel in tables.renderables ) - # Ensure the panel doesn't exceed the console width - panel_width: int = min(table_width, console.width - 2) + # Add panel borders and padding (2 for border + 2 for padding) + panel_width: int = min(table_width + 4, console.width) layout = Layout() layout.split_column( From bb1ac9b4502d696cd3ec183e9dbf4ec41fa894c5 Mon Sep 17 00:00:00 2001 From: Felix Soubelet Date: Thu, 8 Jan 2026 17:12:53 +0100 Subject: [PATCH 67/70] [WIPPP] dopnt care for the panel, though it was the right size --- pyhdtoolkit/scripts/htc_monitor.py | 18 +++--------------- 1 file changed, 3 insertions(+), 15 deletions(-) diff --git a/pyhdtoolkit/scripts/htc_monitor.py b/pyhdtoolkit/scripts/htc_monitor.py index b6cd7926..fe4fee2e 100644 --- a/pyhdtoolkit/scripts/htc_monitor.py +++ b/pyhdtoolkit/scripts/htc_monitor.py @@ -24,7 +24,6 @@ from rich.console import Console, Group from rich.layout import Layout from rich.live import Live -from rich.measure import Measurement from rich.panel import Panel from rich.progress import BarColumn, Progress, TextColumn, TimeRemainingColumn from typer import Option, Typer @@ -95,7 +94,7 @@ def generate_tables_renderable() -> Group: # ----- Progress + Layout helpers ----- # -def make_layout(progress: Progress, tables: Group, console: Console) -> Layout: +def make_layout(progress: Progress, tables: Group) -> Layout: """ Create the main UI layout with the progress bar above the table, dynamically matching the table width (or console width if resized). @@ -106,21 +105,10 @@ def make_layout(progress: Progress, tables: Group, console: Console) -> Layout: The Rich Progress instance for the countdown. table_renderable : Group The Group containing the task and cluster panels. - console : Console - The console, used for width fallback. """ - # Compute max width among all panels in the Group - table_width: int = max( # we add +2 for panel padding/borders - Measurement.get(console, console.options, panel.renderable).maximum # ty:ignore[unresolved-attribute] - for panel in tables.renderables - ) - - # Add panel borders and padding (2 for border + 2 for padding) - panel_width: int = min(table_width + 4, console.width) - layout = Layout() layout.split_column( - Layout(Panel(progress, title="time to Next HTCondor Query", padding=(0, 1), width=panel_width), size=3), + Layout(progress, size=3), Layout(tables, ratio=1), ) return layout @@ -171,7 +159,7 @@ def main( progress.update(task_id, total=wait, completed=0) # We start rendering our layout with progress + table - layout: Layout = make_layout(progress, tables, console) + layout: Layout = make_layout(progress, tables) live.update(layout) # Now we need to update the progress bar until From 78e36a818b341d5e2ee9f90b4287f99d81280c3a Mon Sep 17 00:00:00 2001 From: Felix Soubelet Date: Thu, 8 Jan 2026 17:34:49 +0100 Subject: [PATCH 68/70] no panel, relative sizes, bold main text --- pyhdtoolkit/scripts/htc_monitor.py | 20 ++++++++++++-------- 1 file changed, 12 insertions(+), 8 deletions(-) diff --git a/pyhdtoolkit/scripts/htc_monitor.py b/pyhdtoolkit/scripts/htc_monitor.py index fe4fee2e..e1face79 100644 --- a/pyhdtoolkit/scripts/htc_monitor.py +++ b/pyhdtoolkit/scripts/htc_monitor.py @@ -21,6 +21,7 @@ import time from typing import TYPE_CHECKING +from rich.align import Align from rich.console import Console, Group from rich.layout import Layout from rich.live import Live @@ -94,7 +95,7 @@ def generate_tables_renderable() -> Group: # ----- Progress + Layout helpers ----- # -def make_layout(progress: Progress, tables: Group) -> Layout: +def make_layout(progress: Progress, tables: Group, message: str = "") -> Layout: """ Create the main UI layout with the progress bar above the table, dynamically matching the table width (or console width if resized). @@ -108,9 +109,14 @@ def make_layout(progress: Progress, tables: Group) -> Layout: """ layout = Layout() layout.split_column( - Layout(progress, size=3), - Layout(tables, ratio=1), + Layout(name="header", size=2), # status message + Layout(progress, size=2), # Progress bar + Layout(tables, ratio=1), # Table panels ) + + if message: + layout["header"].update(Align.center(message)) + return layout @@ -134,7 +140,7 @@ def main( # Create re-usable console and progress bar console: Console = Console() progress: Progress = Progress( - TextColumn("[bold]Next HTCondor query[/bold]"), + TextColumn("Time to next HTCondor query: "), BarColumn(), TimeRemainingColumn(), console=console, @@ -144,9 +150,7 @@ def main( # Use an auto-updating live display. The display builds itself # from the created layout we will pass to it. with Live(console=console, refresh_per_second=refresh) as live: - console.log( - f"Querying HTCondor queue every {wait:d} seconds (table display refreshes {refresh:.2f} times/second).\n" - ) + msg = f"[bold]Querying HTCondor queue every {wait:d} seconds (table display refreshes {refresh:.2f} times/second)[/bold]" while True: try: @@ -159,7 +163,7 @@ def main( progress.update(task_id, total=wait, completed=0) # We start rendering our layout with progress + table - layout: Layout = make_layout(progress, tables) + layout: Layout = make_layout(progress, tables, message=msg) live.update(layout) # Now we need to update the progress bar until From 632d21df556e17d9193c5e575cbe7a53c5726450 Mon Sep 17 00:00:00 2001 From: Felix Soubelet Date: Thu, 8 Jan 2026 17:35:54 +0100 Subject: [PATCH 69/70] left align --- pyhdtoolkit/scripts/htc_monitor.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pyhdtoolkit/scripts/htc_monitor.py b/pyhdtoolkit/scripts/htc_monitor.py index e1face79..3456055e 100644 --- a/pyhdtoolkit/scripts/htc_monitor.py +++ b/pyhdtoolkit/scripts/htc_monitor.py @@ -115,7 +115,7 @@ def make_layout(progress: Progress, tables: Group, message: str = "") -> Layout: ) if message: - layout["header"].update(Align.center(message)) + layout["header"].update(Align.left(message)) return layout From 3cb1187edfd560efd92d0df8a5d961469fba4cbc Mon Sep 17 00:00:00 2001 From: Felix Soubelet Date: Thu, 8 Jan 2026 17:48:01 +0100 Subject: [PATCH 70/70] docstring --- pyhdtoolkit/scripts/htc_monitor.py | 66 +++++++++++++++++++++++++++++- 1 file changed, 64 insertions(+), 2 deletions(-) diff --git a/pyhdtoolkit/scripts/htc_monitor.py b/pyhdtoolkit/scripts/htc_monitor.py index 3456055e..156f2c94 100644 --- a/pyhdtoolkit/scripts/htc_monitor.py +++ b/pyhdtoolkit/scripts/htc_monitor.py @@ -12,8 +12,70 @@ build a different monitor script from the functions there. - -TODO: document more this script. +The is registered as a console script called `htc-monitor` in the +environment in which PyhDToolkit is installed. + +It is possible to pass a few options, such as the wait time +between calls to `condor_q`, the refresh rate of the table +display and the logging level for console messages. + +Usage goes as: + +.. code-block:: console + + Usage: python -m pyhdtoolkit.scripts.htc_monitor [OPTIONS] + + Parse the HTCondor queue and display the status in a nice way using `rich`. + + ╭─ Options ───────────────────────────────────────────────────────────────────────────────────────────╮ + │ --wait -w INTEGER RANGE [x>=1] Seconds to wait between calls to `condor_q`. │ + │ [default: 300] │ + │ --refresh -r FLOAT RANGE [x>=0.1] Table display refreshes per second. │ + │ [default: 1] │ + │ --log-level TEXT Console logging level. Can be 'debug', 'info', │ + │ 'warning' and 'error'. │ + │ [default: warning] │ + │ --install-completion Install completion for the current shell. │ + │ --show-completion Show completion for the current shell, to copy │ + │ it or customize the installation. │ + │ --help Show this message and exit. │ + ╰─────────────────────────────────────────────────────────────────────────────────────────────────────╯ + +The script will periodically query HTCondor via `condor_q`, process the output and +display its contents in a nice way using `rich`. +A progress bar will show the time remaining until the next query. + +A typical output (default parameters) looks like: + +.. code-block:: console + + Querying HTCondor queue every 300 seconds (table display refreshes 1.00 times/second) + + Time to next HTCondor query: ━━━━━━━━━━━━━━━━━━━━╺━━━━━━━━━━━━━━━━━━━ 0:02:27 + + ╭────────────────────────────────────────────── Scheduler: bigbird12.cern.ch ──────────────────────────────────────────────╮ + │ │ + │ OWNER BATCH_NAME SUBMITTED DONE RUNNING IDLE TOTAL JOB_IDS │ + │ ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ │ + │ fesoubel 14729581 Thursday, 8 Jan 26 at 10:35 AM (CET) 1 5 _ 6 14729581.1-5 │ + │ fesoubel 14729582 Thursday, 8 Jan 26 at 10:35 AM (CET) _ 6 _ 6 14729582.0-5 │ + │ fesoubel 14729583 Thursday, 8 Jan 26 at 10:36 AM (CET) _ 5 _ 5 14729583.0-4 │ + │ fesoubel 14729584 Thursday, 8 Jan 26 at 10:36 AM (CET) _ 5 _ 5 14729584.0-4 │ + │ │ + ╰──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯ + ╭────────────────────────────────────────────────── bigbird12 Statistics ──────────────────────────────────────────────────╮ + │ ────────────────────────────────────────────────────────────────────────────────────────────────────────────────────── │ + │ SOURCE JOBS COMPLETED RUNNING IDLE HELD SUSPENDED REMOVED │ + │ ────────────────────────────────────────────────────────────────────────────────────────────────────────────────────── │ + │ Query 21 0 21 0 0 0 0 │ + │ fesoubel 21 0 21 0 0 0 0 │ + │ All Users 23387 0 9834 13284 269 0 0 │ + │ ────────────────────────────────────────────────────────────────────────────────────────────────────────────────────── │ + ╰──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯ + +The script is hardcoded to expect outputs from CERN's HTCondor setup. +In case you would like to adapt it to your own HTCondor installation, +or request new features, please open an issue on the GitHub repository. """ from __future__ import annotations