From 95f46d48682a985fbc13a5af7e8aef05c5ef7d63 Mon Sep 17 00:00:00 2001 From: Bojan Todorkov Date: Mon, 14 Jul 2025 18:33:25 +0200 Subject: [PATCH 01/17] Extend documentation with uv and pre-commit Add description of how to contribute to this code- base and mention pre-commit. The latter has yet to be initialized properly. --- .python-version | 1 + README.md | 8 + pyproject.toml | 1 + uv.lock | 1362 +++++++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 1372 insertions(+) create mode 100644 .python-version create mode 100644 uv.lock diff --git a/.python-version b/.python-version new file mode 100644 index 0000000..c8cfe39 --- /dev/null +++ b/.python-version @@ -0,0 +1 @@ +3.10 diff --git a/README.md b/README.md index 56b064b..ace1ce4 100644 --- a/README.md +++ b/README.md @@ -64,6 +64,14 @@ It is recommended that you add this line to your .bash_profile file (or equivele There are example scripts and Jupyter notebooks available on [GitHub demonstrating how to use pySAS](https://github.com/XMMGOF/pysas/tree/main/documentation). We are expanding the number of example scripts and Jupyter notebooks. +### Contributing to PySAS + +We are using the package manager [uv](https://docs.astral.sh/uv/). This way every developer has the same python and package versions. Before editing the code, install uv ([installing uv](https://docs.astral.sh/uv/getting-started/installation/)) on your machine. + +When you have uv installed, `cd` into the root directory of `pysas` in your favorite terminal and execute `uv sync`. This will create a `.venv` directory in the root directory, which contains all the packages. Point your IDE to use `.venv/bin/python` as the python executable for this project. + +One of the installed packages is [`pre-commit`](https://pre-commit.com), but it is not yet initialized. This will be done in near future. + ### FAQ Q: Will this break my SAS inatallation? diff --git a/pyproject.toml b/pyproject.toml index 0fda696..747d836 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -10,6 +10,7 @@ dependencies = [ "beautifultable>=1.1.0", "loguru>=0.7.3", "matplotlib>=3.10.3", + "pre-commit>=4.2.0", "pyds9>=1.8.1", "pypdf>=5.6.0", "pyqt5>=5.15.11", diff --git a/uv.lock b/uv.lock new file mode 100644 index 0000000..ec2e256 --- /dev/null +++ b/uv.lock @@ -0,0 +1,1362 @@ +version = 1 +revision = 2 +requires-python = ">=3.10" +resolution-markers = [ + "python_full_version >= '3.11'", + "python_full_version < '3.11'", +] + +[[package]] +name = "astropy" +version = "6.1.7" +source = { registry = "https://pypi.org/simple" } +resolution-markers = [ + "python_full_version < '3.11'", +] +dependencies = [ + { name = "astropy-iers-data", marker = "python_full_version < '3.11'" }, + { name = "numpy", version = "2.2.6", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version < '3.11'" }, + { name = "packaging", marker = "python_full_version < '3.11'" }, + { name = "pyerfa", marker = "python_full_version < '3.11'" }, + { name = "pyyaml", marker = "python_full_version < '3.11'" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/8a/f8/9c6675ab4c646b95aae2762d108f6be4504033d91bd50da21daa62cab5ce/astropy-6.1.7.tar.gz", hash = "sha256:a405ac186306b6cb152e6df2f7444ab8bd764e4127d7519da1b3ae4dd65357ef", size = 7063411, upload-time = "2024-11-22T21:22:34.373Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/6a/4f/27f91eb9cdaa37835e52496dcad00fd89969ef5154795697987d031d0605/astropy-6.1.7-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:be954c5f7707a089609053665aeb76493b79e5c4753c39486761bc6d137bf040", size = 6531137, upload-time = "2024-11-22T21:21:30.502Z" }, + { url = "https://files.pythonhosted.org/packages/4b/f2/fb2c6c1d31c21df0d4409ecd5e9788795be6f8f80b67008c8191488d55cf/astropy-6.1.7-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:b5e48df5ab2e3e521e82a7233a4b1159d071e64e6cbb76c45415dc68d3b97af1", size = 6410376, upload-time = "2024-11-22T21:21:32.986Z" }, + { url = "https://files.pythonhosted.org/packages/fd/68/65ad3ea77440df2e8625d8fee585d5fc6049f33a61e49221f91d8de0e3df/astropy-6.1.7-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:55c78252633c644361e2f7092d71f80ef9c2e6649f08d97711d9f19af514aedc", size = 9892774, upload-time = "2024-11-22T21:21:34.823Z" }, + { url = "https://files.pythonhosted.org/packages/b4/41/e366fc5baff41f7b433f07a46c053a24459e93d2912690d099f0eefabfc3/astropy-6.1.7-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:985e5e74489d23f1a11953b6b283fccde3f46cb6c68fee4f7228e5f6d8350ba9", size = 9962419, upload-time = "2024-11-22T21:21:36.863Z" }, + { url = "https://files.pythonhosted.org/packages/1e/a0/e6c1ef80f7e20fb600b3af742d227e6356704dbda3763ff1d76a53a0fd7b/astropy-6.1.7-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:dc2ea28ed41a3d92c39b1481d9c5be016ae58d68f144f3fd8cecffe503525bab", size = 9987760, upload-time = "2024-11-22T21:21:39.736Z" }, + { url = "https://files.pythonhosted.org/packages/49/93/6b23e75d690763a9d702038c74ea9a74181a278fe362fbeecea35b691e4a/astropy-6.1.7-cp310-cp310-win32.whl", hash = "sha256:4e4badadd8dfa5dca08fd86e9a50a3a91af321975859f5941579e6b7ce9ba199", size = 6274137, upload-time = "2024-11-22T21:21:42.178Z" }, + { url = "https://files.pythonhosted.org/packages/6e/e1/af92dc2132547e3998476a4b0ab19d15c50d8ec1d85e658fe6503e125fd1/astropy-6.1.7-cp310-cp310-win_amd64.whl", hash = "sha256:8d7f6727689288ee08fc0a4a297fc7e8089d01718321646bd00fea0906ad63dc", size = 6394810, upload-time = "2024-11-22T21:21:43.843Z" }, + { url = "https://files.pythonhosted.org/packages/4f/5e/d31204823764f6e5fa4820c1b4f49f8eef7cf691b796ec389f41b4f5a699/astropy-6.1.7-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:09edca01276ee63f7b2ff511da9bfb432068ba3242e27ef27d76e5a171087b7e", size = 6531221, upload-time = "2024-11-22T21:21:46.2Z" }, + { url = "https://files.pythonhosted.org/packages/22/e2/ae5dd6d9272e41619d85df4e4a03cf06acea8bcb44c42fe67e5cd04ae131/astropy-6.1.7-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:072f62a67992393beb016dc80bee8fb994fda9aa69e945f536ed8ac0e51291e6", size = 6409477, upload-time = "2024-11-22T21:21:47.862Z" }, + { url = "https://files.pythonhosted.org/packages/01/ed/9bc17beb457943ee04b8c85614ddb4a64a4a91597340dca28332e112209d/astropy-6.1.7-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b2706156d3646f9c9a7fc810475d8ab0df4c717beefa8326552576a0f8ddca20", size = 10150734, upload-time = "2024-11-22T21:21:49.847Z" }, + { url = "https://files.pythonhosted.org/packages/39/38/1c5263f0d775def518707ccd1cf9d4df1d99d523fc148df9e38aa5ba9d54/astropy-6.1.7-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:fcd99e627692f8e58bb3097d330bfbd109a22e00dab162a67f203b0a0601ad2c", size = 10210679, upload-time = "2024-11-22T21:21:52.011Z" }, + { url = "https://files.pythonhosted.org/packages/32/d1/7365e16b0158f755977a5bdbd329df40a9772b0423a1d5075aba9246673f/astropy-6.1.7-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:b0ebbcb637b2e9bcb73011f2b7890d7a3f5a41b66ccaad7c28f065e81e28f0b2", size = 10245960, upload-time = "2024-11-22T21:21:54.785Z" }, + { url = "https://files.pythonhosted.org/packages/e9/b6/4dc6f9ef1c17738b8ebd8922bc1c6fec48542ccfe5124b6719737b012b8c/astropy-6.1.7-cp311-cp311-win32.whl", hash = "sha256:192b12ede49cd828362ab1a6ede2367fe203f4d851804ec22fa92e009a524281", size = 6272124, upload-time = "2024-11-22T21:21:57.504Z" }, + { url = "https://files.pythonhosted.org/packages/ba/c6/b5f33597bfbc1afad0640b20000633127dfa0a4295b607a0439f45546d9a/astropy-6.1.7-cp311-cp311-win_amd64.whl", hash = "sha256:3cac64bcdf570c947019bd2bc96711eeb2c7763afe192f18c9551e52a6c296b2", size = 6396627, upload-time = "2024-11-22T21:21:59.913Z" }, + { url = "https://files.pythonhosted.org/packages/46/2b/007c888fead170c714ecdcf56bc59e8d3252776bd3f16e1797158a46f65d/astropy-6.1.7-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:f2a8bcbb1306052cc38c9eed2c9331bfafe2582b499a7321946abf74b26eb256", size = 6535604, upload-time = "2024-11-22T21:22:02.515Z" }, + { url = "https://files.pythonhosted.org/packages/8e/4c/cc30c9b1440f4a2f1f52845873ae3f8f7c4343261e516603a35546574ed7/astropy-6.1.7-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:eaf88878684f9d31aff36475c90d101f4cff22fdd4fd50098d9950fd56994df7", size = 6415117, upload-time = "2024-11-22T21:22:04.484Z" }, + { url = "https://files.pythonhosted.org/packages/12/2d/9985b8b4225c2495c4e64713d1630937c83af863db606d12676b72b4f651/astropy-6.1.7-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1cb8cd231e53556e4eebe0393ea95a8cea6b2ff4187c95ac4ff8b17e7a8da823", size = 10177861, upload-time = "2024-11-22T21:22:06.043Z" }, + { url = "https://files.pythonhosted.org/packages/b7/b6/63ccb085757638d15f0f9d6f2dffaccce7785236fe8bf23e4b380a333ce0/astropy-6.1.7-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:5ad36334d138a4f71d6fdcf225a98ad1dad6c343da4362d5a47a71f5c9da3ca9", size = 10258014, upload-time = "2024-11-22T21:22:08.164Z" }, + { url = "https://files.pythonhosted.org/packages/c8/ee/a6af891802de463f70e3fddf09f3aeb1d46dde87885e2245d25a2ac46948/astropy-6.1.7-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:dd731c526869d0c68507be7b31dd10871b7c44d310bb5495476505560c83cd33", size = 10277363, upload-time = "2024-11-22T21:22:10.331Z" }, + { url = "https://files.pythonhosted.org/packages/dd/98/b253583f9de7033f03a7c5f5314b9e93177725a2020e0f36d338d242bf0e/astropy-6.1.7-cp312-cp312-win32.whl", hash = "sha256:662bacd7ae42561e038cbd85eea3b749308cf3575611a745b60f034d3350c97a", size = 6271741, upload-time = "2024-11-22T21:22:12.696Z" }, + { url = "https://files.pythonhosted.org/packages/7a/63/e1b5f01e6735ed8f9d62d3eed5f226bc0ab516ab8558ffaccf6d4185f91d/astropy-6.1.7-cp312-cp312-win_amd64.whl", hash = "sha256:5b4d02a98a0bf91ff7fd4ef0bd0ecca83c9497338cb88b61ec9f971350688222", size = 6396352, upload-time = "2024-11-22T21:22:14.525Z" }, + { url = "https://files.pythonhosted.org/packages/73/9d/21d2e61080a81e7e1f5e5006204a76e70588aa1a88aa9044c2d203578d07/astropy-6.1.7-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:fbeaf04427987c0c6fa2e579eb40011802b06fba6b3a7870e082d5c693564e1b", size = 6528360, upload-time = "2024-11-22T21:22:16.275Z" }, + { url = "https://files.pythonhosted.org/packages/d5/3e/b999ec6cd607c512e66d8a138443361eb88899760c7cb8517a66155732ee/astropy-6.1.7-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:ab6e88241a14185b9404b02246329185b70292984aa0616b20a0628dfe4f4ebb", size = 6407905, upload-time = "2024-11-22T21:22:18.035Z" }, + { url = "https://files.pythonhosted.org/packages/db/2d/44557c63688c2ed03d0d72b4f27fc30fc1ea250aeb5ebd939796c5f98bee/astropy-6.1.7-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a0529c75565feaabb629946806b4763ae7b02069aeff4c3b56a69e8a9e638500", size = 10106849, upload-time = "2024-11-22T21:22:20.393Z" }, + { url = "https://files.pythonhosted.org/packages/66/bc/993552eb932dec528fe6b95f511e918473ea4406dee4b17c223f3fd8a919/astropy-6.1.7-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9c5ec347631da77573fc729ba04e5d89a3bc94500bf6037152a2d0f9965ae1ce", size = 10194766, upload-time = "2024-11-22T21:22:23.116Z" }, + { url = "https://files.pythonhosted.org/packages/9f/f3/3c5282762c8a5746e7752e46a1e328c79a5d0186d96cfd0995bdf976e1f9/astropy-6.1.7-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:dc496f87aaccaa5c6624acc985b8770f039c5bbe74b120c8ed7bad3698e24e1b", size = 10219291, upload-time = "2024-11-22T21:22:26.079Z" }, + { url = "https://files.pythonhosted.org/packages/d8/52/949bb79df9c03f56d0ae93ac62f2616fe3e67db51677bf412473bf6d077e/astropy-6.1.7-cp313-cp313-win32.whl", hash = "sha256:b1e01d534383c038dbf8664b964fa4ea818c7419318830d3c732c750c64115c6", size = 6269501, upload-time = "2024-11-22T21:22:28.468Z" }, + { url = "https://files.pythonhosted.org/packages/a1/da/f369561a67061dd42e13c7f758b393ae90319dbbcf7e301a18ce3fa43ec6/astropy-6.1.7-cp313-cp313-win_amd64.whl", hash = "sha256:af08cf2b0368f1ea585eb26a55d99a2de9e9b0bd30aba84b5329059c3ec33590", size = 6393207, upload-time = "2024-11-22T21:22:31.797Z" }, +] + +[[package]] +name = "astropy" +version = "7.1.0" +source = { registry = "https://pypi.org/simple" } +resolution-markers = [ + "python_full_version >= '3.11'", +] +dependencies = [ + { name = "astropy-iers-data", marker = "python_full_version >= '3.11'" }, + { name = "numpy", version = "2.3.0", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.11'" }, + { name = "packaging", marker = "python_full_version >= '3.11'" }, + { name = "pyerfa", marker = "python_full_version >= '3.11'" }, + { name = "pyyaml", marker = "python_full_version >= '3.11'" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/83/91/124d020cea78e4e4b6db7ff726c2c2e4a5865293d0a4355d13b0312d99f1/astropy-7.1.0.tar.gz", hash = "sha256:c8f254322295b1b8cf24303d6f155bf7efdb6c1282882b966ce3040eff8c53c5", size = 6976116, upload-time = "2025-05-20T13:40:10.557Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/fe/0d/ed4d605f8dfa8ec236dd2c91489b24d223fa98f41f181437f6d15a98190d/astropy-7.1.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:8e2bc5cb91dc319bcf65ee08c68abea617c52b5d042d245542a4853b07269233", size = 6378504, upload-time = "2025-05-20T13:39:29.056Z" }, + { url = "https://files.pythonhosted.org/packages/de/18/38e92baafca43f654704d7ca8cd0efdd626d9987d9918de08abe8a1cb297/astropy-7.1.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:fba97e3d99ad48540b6eb7c6f7849e57dd6aaf9d9d48707b227bf39ac77c6368", size = 6303097, upload-time = "2025-05-20T13:39:31.586Z" }, + { url = "https://files.pythonhosted.org/packages/f9/03/cca1b2259ab22dae67a7d7a7b22454206c0fb5384e99b00d2326663fbed6/astropy-7.1.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a58498f9549a0e94a1f2cd48ddb96c0bed7b0375a6362ee4025f19d6bd114f9a", size = 10080125, upload-time = "2025-05-20T13:39:33.034Z" }, + { url = "https://files.pythonhosted.org/packages/80/a1/87254b4f8ec58308ad745574da66fd205ba59da74cdf7e8319d442bb3161/astropy-7.1.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7694e0b2ffc5fa60c47a55667bdfda98cbae8df736f60cc57afbe38bc5c98b41", size = 10087022, upload-time = "2025-05-20T13:39:35.315Z" }, + { url = "https://files.pythonhosted.org/packages/d7/4d/96f3806e6cf50dd8bd08ccac668e54d3d66b43bf5574bf27bf5fbad4de74/astropy-7.1.0-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:83fe4c581bbdf1cbaeab1efc58891e4433d729412847f4d0788c870fee709432", size = 10120923, upload-time = "2025-05-20T13:39:39.781Z" }, + { url = "https://files.pythonhosted.org/packages/a3/c2/0f089b4c387fc6a4b4ac9760b8a5ec3b3552af7ecf4d3a372963cd5d43e2/astropy-7.1.0-cp311-cp311-win32.whl", hash = "sha256:a2d277cf0d34748bfc23bb6b4d1974f058c8541ec92113cb00db06eebe5a2862", size = 6151431, upload-time = "2025-05-20T13:39:41.974Z" }, + { url = "https://files.pythonhosted.org/packages/3f/7e/13b136c020e009daf8481163087f287c634cd44aad600becc6cdafa6c0b1/astropy-7.1.0-cp311-cp311-win_amd64.whl", hash = "sha256:3b66b8dbb678fca9a811f24227a953a3c2f7b02c951c5b2dee3ab6853ac6e1b0", size = 6278397, upload-time = "2025-05-20T13:39:43.709Z" }, + { url = "https://files.pythonhosted.org/packages/cf/9a/ed2b35b55e28a6317471b61456d2feda7798b2dd3601e17859620e8eae4c/astropy-7.1.0-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:e0fec2f4b5265caab68020eaa320704e7ce9433ae8dbea75c300468fed695437", size = 6381273, upload-time = "2025-05-20T13:39:45.481Z" }, + { url = "https://files.pythonhosted.org/packages/5c/45/333bc1072f3b2ac31aec33063bb7122661405a97cb7fec702e95af707bd4/astropy-7.1.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:e4bb022f863cf13eefeb406692f58824c0d9bdb1aa36ae786e87c096d8ebdd07", size = 6301716, upload-time = "2025-05-20T13:39:47.339Z" }, + { url = "https://files.pythonhosted.org/packages/58/90/bfb7a1b5d9e3401967e351cf31add576cddf7466d2030cc6f4d1d841a18d/astropy-7.1.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c811a4aedd8fbf6d7611d64d40af1f0c1c1e6621e5992e7e1a7b5fec47dc1fa1", size = 10096600, upload-time = "2025-05-20T13:39:49.169Z" }, + { url = "https://files.pythonhosted.org/packages/fb/69/a34f20db7146912f25e2487c5283f1ae2aed5d24f615fa976439ece35f7e/astropy-7.1.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:654261df547c150e5b6a022f3785f47a2e547e0cc1c06fbcf6293b5f4e85722a", size = 10160320, upload-time = "2025-05-20T13:39:51.079Z" }, + { url = "https://files.pythonhosted.org/packages/7a/be/0b874f551acbac27ff3d5d73bdf3c0860a8b78c6db574b19e6d0b7d363e4/astropy-7.1.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:6bd25761ba1385bb99a189401fbc486e0884d97129e271b655b6efa956a12a77", size = 10137307, upload-time = "2025-05-20T13:39:53.175Z" }, + { url = "https://files.pythonhosted.org/packages/ea/1c/132241ab2006a52b4809ee82a71fde793c0159916ae45dae374b0412b037/astropy-7.1.0-cp312-cp312-win32.whl", hash = "sha256:f637e39622b23750a12b19ab4642f2e3970f6cb84f2228587725f15bf1d80d03", size = 6152433, upload-time = "2025-05-20T13:39:54.933Z" }, + { url = "https://files.pythonhosted.org/packages/11/39/0a38241008905a9c1048f7b351310deee71cf42e0de1f929e84a10878864/astropy-7.1.0-cp312-cp312-win_amd64.whl", hash = "sha256:06ba650db237557912fdd7bb8ffdd87838e23e58b0fa0001b4d43c2bb5a79412", size = 6279663, upload-time = "2025-05-20T13:39:56.274Z" }, + { url = "https://files.pythonhosted.org/packages/a3/d6/ec68703aff787ca1bb2ed92a109256a6e4d9975aeee0b4bd2b0ab84b2993/astropy-7.1.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:116149abdebafab193f7ca16427bd6bb4afc111677c78c32f48cffbc0ecb6a18", size = 6375607, upload-time = "2025-05-20T13:39:57.6Z" }, + { url = "https://files.pythonhosted.org/packages/2b/79/0f6eacbe575c3b677d70193c22b68c3a95bec68204ccf53068b657c7ed06/astropy-7.1.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:734d5e93e76d2e2175f991b17ca130463f2edb56c107fbc07c6532ca461a6ea7", size = 6296640, upload-time = "2025-05-20T13:39:58.973Z" }, + { url = "https://files.pythonhosted.org/packages/c7/c1/06bd8bd17b2302c05d75079ca89d79825dede63c00876e439ec91f120405/astropy-7.1.0-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1fd94f755f2e9104c5caf0afe69175d2620708828233d387c1dad0044e79f543", size = 10030192, upload-time = "2025-05-20T13:40:01.129Z" }, + { url = "https://files.pythonhosted.org/packages/17/ce/f9e103e6be3d801cadffef8eb814bd10e4de3603b9ba9f97dd41c6a59bde/astropy-7.1.0-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:49effea6de855dcdba09a211d51ca279766c66284c8db3d911b4523bbd96eae9", size = 10079889, upload-time = "2025-05-20T13:40:03.076Z" }, + { url = "https://files.pythonhosted.org/packages/a3/fe/605a09e74b03ea2981632cd9a9a3720bd8d232ddaa729fc63ce46d538218/astropy-7.1.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:52709e6bbe65c6d6c2a342506ad8c2801ff2aed80cc0a5d7817387122e0ac616", size = 10084024, upload-time = "2025-05-20T13:40:04.776Z" }, + { url = "https://files.pythonhosted.org/packages/af/e9/8259c4699227e5ee71d5d15a297f1e9469b99a980a1fd3140ecf68e98c4d/astropy-7.1.0-cp313-cp313-win32.whl", hash = "sha256:a77d07a104ec24ed7f8a45de3935f46071551aa2eb6d6b62efebdc888f65b6d6", size = 6150536, upload-time = "2025-05-20T13:40:06.638Z" }, + { url = "https://files.pythonhosted.org/packages/0b/dd/d9c55247172f7156696d85c9146b64b41c30405bf86b775a731bed4d52f8/astropy-7.1.0-cp313-cp313-win_amd64.whl", hash = "sha256:8e317f34e33a8f5517bc9fc6fbc005f42730d3be7d2820ef41e0468bcb796843", size = 6278127, upload-time = "2025-05-20T13:40:08.643Z" }, +] + +[[package]] +name = "astropy-iers-data" +version = "0.2025.6.16.0.38.47" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/63/ae/efd931d47653f474afb1154d9181f885bf3f82854dcdd979a9e2838470c5/astropy_iers_data-0.2025.6.16.0.38.47.tar.gz", hash = "sha256:58c984976506b8a5c1c969aafe8744b286111d98c8623e66aecc45db9e777121", size = 1899704, upload-time = "2025-06-16T00:39:20.529Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/3c/35/e4b67e87d7ff182b59047db09dce11c7154273eee428c98fe0828adbf3d7/astropy_iers_data-0.2025.6.16.0.38.47-py3-none-any.whl", hash = "sha256:c8c2c999bb9fa987c89c737bc7e71d83f8a6c8fd874ef03b0adc196c1432e20e", size = 1955135, upload-time = "2025-06-16T00:39:18.731Z" }, +] + +[[package]] +name = "astroquery" +version = "0.4.10" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "astropy", version = "6.1.7", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version < '3.11'" }, + { name = "astropy", version = "7.1.0", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.11'" }, + { name = "beautifulsoup4" }, + { name = "html5lib" }, + { name = "keyring" }, + { name = "numpy", version = "2.2.6", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version < '3.11'" }, + { name = "numpy", version = "2.3.0", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.11'" }, + { name = "pyvo" }, + { name = "requests" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/67/6b/a3757b4e383679d39e8fc75262c1747dcdce1b2fd540984e409d0b2fc7d1/astroquery-0.4.10.tar.gz", hash = "sha256:eacd91e9da378e641740fbc3123850daa83ba0926a6fff4c40ccbf5dc6d5a406", size = 12533999, upload-time = "2025-03-18T19:21:44.925Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/73/8c/64ac07bf58f14d861127d8583122e10686e23161cc9e874b979a35810065/astroquery-0.4.10-py3-none-any.whl", hash = "sha256:43a0255766bfe1f7a86f528e19832d1a6428400bda348e9f0ec970cac2ee81ec", size = 11119748, upload-time = "2025-03-18T19:21:38.494Z" }, +] + +[[package]] +name = "backports-tarfile" +version = "1.2.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/86/72/cd9b395f25e290e633655a100af28cb253e4393396264a98bd5f5951d50f/backports_tarfile-1.2.0.tar.gz", hash = "sha256:d75e02c268746e1b8144c278978b6e98e85de6ad16f8e4b0844a154557eca991", size = 86406, upload-time = "2024-05-28T17:01:54.731Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/b9/fa/123043af240e49752f1c4bd24da5053b6bd00cad78c2be53c0d1e8b975bc/backports.tarfile-1.2.0-py3-none-any.whl", hash = "sha256:77e284d754527b01fb1e6fa8a1afe577858ebe4e9dad8919e34c862cb399bc34", size = 30181, upload-time = "2024-05-28T17:01:53.112Z" }, +] + +[[package]] +name = "beautifulsoup4" +version = "4.13.4" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "soupsieve" }, + { name = "typing-extensions" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/d8/e4/0c4c39e18fd76d6a628d4dd8da40543d136ce2d1752bd6eeeab0791f4d6b/beautifulsoup4-4.13.4.tar.gz", hash = "sha256:dbb3c4e1ceae6aefebdaf2423247260cd062430a410e38c66f2baa50a8437195", size = 621067, upload-time = "2025-04-15T17:05:13.836Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/50/cd/30110dc0ffcf3b131156077b90e9f60ed75711223f306da4db08eff8403b/beautifulsoup4-4.13.4-py3-none-any.whl", hash = "sha256:9bbbb14bfde9d79f38b8cd5f8c7c85f4b8f2523190ebed90e950a8dea4cb1c4b", size = 187285, upload-time = "2025-04-15T17:05:12.221Z" }, +] + +[[package]] +name = "beautifultable" +version = "1.1.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "wcwidth" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/86/a6/8aa4b731d0d53bd375411cb846e938028d7dda234d4966324d2e8f240588/beautifultable-1.1.0.tar.gz", hash = "sha256:040bc987444965678f4ffdfa2f17ac357f1a13e5875b161c9a1899b375319d17", size = 40190, upload-time = "2022-05-06T17:20:59.879Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/85/47/b6a0dcf1b55866e27492a59c250a8bc36cd4bdb95c2ecc76878cf18a21b8/beautifultable-1.1.0-py2.py3-none-any.whl", hash = "sha256:b34053a581976c4c23064bb0e918a7f6f22273cf196c787946db323a6a2b7d84", size = 28630, upload-time = "2022-05-06T17:20:58.125Z" }, +] + +[[package]] +name = "certifi" +version = "2025.6.15" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/73/f7/f14b46d4bcd21092d7d3ccef689615220d8a08fb25e564b65d20738e672e/certifi-2025.6.15.tar.gz", hash = "sha256:d747aa5a8b9bbbb1bb8c22bb13e22bd1f18e9796defa16bab421f7f7a317323b", size = 158753, upload-time = "2025-06-15T02:45:51.329Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/84/ae/320161bd181fc06471eed047ecce67b693fd7515b16d495d8932db763426/certifi-2025.6.15-py3-none-any.whl", hash = "sha256:2e0c7ce7cb5d8f8634ca55d2ba7e6ec2689a2fd6537d8dec1296a477a4910057", size = 157650, upload-time = "2025-06-15T02:45:49.977Z" }, +] + +[[package]] +name = "cffi" +version = "1.17.1" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "pycparser" }, +] +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/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/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" }, + { url = "https://files.pythonhosted.org/packages/2e/ea/70ce63780f096e16ce8588efe039d3c4f91deb1dc01e9c73a287939c79a6/cffi-1.17.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a1ed2dd2972641495a3ec98445e09766f077aee98a1c896dcb4ad0d303628e41", size = 469200, upload-time = "2024-09-04T20:43:57.891Z" }, + { url = "https://files.pythonhosted.org/packages/1c/a0/a4fa9f4f781bda074c3ddd57a572b060fa0df7655d2a4247bbe277200146/cffi-1.17.1-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:46bf43160c1a35f7ec506d254e5c890f3c03648a4dbac12d624e4490a7046cd1", size = 477235, upload-time = "2024-09-04T20:44:00.18Z" }, + { url = "https://files.pythonhosted.org/packages/62/12/ce8710b5b8affbcdd5c6e367217c242524ad17a02fe5beec3ee339f69f85/cffi-1.17.1-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:a24ed04c8ffd54b0729c07cee15a81d964e6fee0e3d4d342a27b020d22959dc6", size = 459721, upload-time = "2024-09-04T20:44:01.585Z" }, + { url = "https://files.pythonhosted.org/packages/ff/6b/d45873c5e0242196f042d555526f92aa9e0c32355a1be1ff8c27f077fd37/cffi-1.17.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:610faea79c43e44c71e1ec53a554553fa22321b65fae24889706c0a84d4ad86d", size = 467242, upload-time = "2024-09-04T20:44:03.467Z" }, + { url = "https://files.pythonhosted.org/packages/1a/52/d9a0e523a572fbccf2955f5abe883cfa8bcc570d7faeee06336fbd50c9fc/cffi-1.17.1-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:a9b15d491f3ad5d692e11f6b71f7857e7835eb677955c00cc0aefcd0669adaf6", size = 477999, upload-time = "2024-09-04T20:44:05.023Z" }, + { url = "https://files.pythonhosted.org/packages/44/74/f2a2460684a1a2d00ca799ad880d54652841a780c4c97b87754f660c7603/cffi-1.17.1-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:de2ea4b5833625383e464549fec1bc395c1bdeeb5f25c4a3a82b5a8c756ec22f", size = 454242, upload-time = "2024-09-04T20:44:06.444Z" }, + { url = "https://files.pythonhosted.org/packages/f8/4a/34599cac7dfcd888ff54e801afe06a19c17787dfd94495ab0c8d35fe99fb/cffi-1.17.1-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:fc48c783f9c87e60831201f2cce7f3b2e4846bf4d8728eabe54d60700b318a0b", size = 478604, upload-time = "2024-09-04T20:44:08.206Z" }, + { url = "https://files.pythonhosted.org/packages/cc/b6/db007700f67d151abadf508cbfd6a1884f57eab90b1bb985c4c8c02b0f28/cffi-1.17.1-cp312-cp312-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:1257bdabf294dceb59f5e70c64a3e2f462c30c7ad68092d01bbbfb1c16b1ba36", size = 454803, upload-time = "2024-09-04T20:44:15.231Z" }, + { url = "https://files.pythonhosted.org/packages/1a/df/f8d151540d8c200eb1c6fba8cd0dfd40904f1b0682ea705c36e6c2e97ab3/cffi-1.17.1-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:da95af8214998d77a98cc14e3a3bd00aa191526343078b530ceb0bd710fb48a5", size = 478850, upload-time = "2024-09-04T20:44:17.188Z" }, + { url = "https://files.pythonhosted.org/packages/28/c0/b31116332a547fd2677ae5b78a2ef662dfc8023d67f41b2a83f7c2aa78b1/cffi-1.17.1-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:d63afe322132c194cf832bfec0dc69a99fb9bb6bbd550f161a49e9e855cc78ff", size = 485729, upload-time = "2024-09-04T20:44:18.688Z" }, + { url = "https://files.pythonhosted.org/packages/91/2b/9a1ddfa5c7f13cab007a2c9cc295b70fbbda7cb10a286aa6810338e60ea1/cffi-1.17.1-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:f79fc4fc25f1c8698ff97788206bb3c2598949bfe0fef03d299eb1b5356ada99", size = 471256, upload-time = "2024-09-04T20:44:20.248Z" }, + { url = "https://files.pythonhosted.org/packages/b2/d5/da47df7004cb17e4955df6a43d14b3b4ae77737dff8bf7f8f333196717bf/cffi-1.17.1-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b62ce867176a75d03a665bad002af8e6d54644fad99a3c70905c543130e39d93", size = 479424, upload-time = "2024-09-04T20:44:21.673Z" }, + { url = "https://files.pythonhosted.org/packages/0b/ac/2a28bcf513e93a219c8a4e8e125534f4f6db03e3179ba1c45e949b76212c/cffi-1.17.1-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:386c8bf53c502fff58903061338ce4f4950cbdcb23e2902d86c0f722b786bbe3", size = 484568, upload-time = "2024-09-04T20:44:23.245Z" }, + { url = "https://files.pythonhosted.org/packages/d4/38/ca8a4f639065f14ae0f1d9751e70447a261f1a30fa7547a828ae08142465/cffi-1.17.1-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:4ceb10419a9adf4460ea14cfd6bc43d08701f0835e979bf821052f1805850fe8", size = 488736, upload-time = "2024-09-04T20:44:24.757Z" }, + { url = "https://files.pythonhosted.org/packages/0e/2d/eab2e858a91fdff70533cab61dcff4a1f55ec60425832ddfdc9cd36bc8af/cffi-1.17.1-cp313-cp313-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:d01b12eeeb4427d3110de311e1774046ad344f5b1a7403101878976ecd7a10f3", size = 454792, upload-time = "2024-09-04T20:44:32.01Z" }, + { url = "https://files.pythonhosted.org/packages/75/b2/fbaec7c4455c604e29388d55599b99ebcc250a60050610fadde58932b7ee/cffi-1.17.1-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:706510fe141c86a69c8ddc029c7910003a17353970cff3b904ff0686a5927683", size = 478893, upload-time = "2024-09-04T20:44:33.606Z" }, + { url = "https://files.pythonhosted.org/packages/4f/b7/6e4a2162178bf1935c336d4da8a9352cccab4d3a5d7914065490f08c0690/cffi-1.17.1-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:de55b766c7aa2e2a3092c51e0483d700341182f08e67c63630d5b6f200bb28e5", size = 485810, upload-time = "2024-09-04T20:44:35.191Z" }, + { url = "https://files.pythonhosted.org/packages/c7/8a/1d0e4a9c26e54746dc08c2c6c037889124d4f59dffd853a659fa545f1b40/cffi-1.17.1-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:c59d6e989d07460165cc5ad3c61f9fd8f1b4796eacbd81cee78957842b834af4", size = 471200, upload-time = "2024-09-04T20:44:36.743Z" }, + { url = "https://files.pythonhosted.org/packages/26/9f/1aab65a6c0db35f43c4d1b4f580e8df53914310afc10ae0397d29d697af4/cffi-1.17.1-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:dd398dbc6773384a17fe0d3e7eeb8d1a21c2200473ee6806bb5e6a8e62bb73dd", size = 479447, upload-time = "2024-09-04T20:44:38.492Z" }, + { url = "https://files.pythonhosted.org/packages/5f/e4/fb8b3dd8dc0e98edf1135ff067ae070bb32ef9d509d6cb0f538cd6f7483f/cffi-1.17.1-cp313-cp313-musllinux_1_1_aarch64.whl", hash = "sha256:3edc8d958eb099c634dace3c7e16560ae474aa3803a5df240542b305d14e14ed", size = 484358, upload-time = "2024-09-04T20:44:40.046Z" }, + { url = "https://files.pythonhosted.org/packages/f1/47/d7145bf2dc04684935d57d67dff9d6d795b2ba2796806bb109864be3a151/cffi-1.17.1-cp313-cp313-musllinux_1_1_x86_64.whl", hash = "sha256:72e72408cad3d5419375fc87d289076ee319835bdfa2caad331e377589aebba9", size = 488469, upload-time = "2024-09-04T20:44:41.616Z" }, +] + +[[package]] +name = "cfgv" +version = "3.4.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/11/74/539e56497d9bd1d484fd863dd69cbbfa653cd2aa27abfe35653494d85e94/cfgv-3.4.0.tar.gz", hash = "sha256:e52591d4c5f5dead8e0f673fb16db7949d2cfb3f7da4582893288f0ded8fe560", size = 7114, upload-time = "2023-08-12T20:38:17.776Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/c5/55/51844dd50c4fc7a33b653bfaba4c2456f06955289ca770a5dbd5fd267374/cfgv-3.4.0-py2.py3-none-any.whl", hash = "sha256:b7265b1f29fd3316bfcd2b330d63d024f2bfd8bcb8b0272f8e19a504856c48f9", size = 7249, upload-time = "2023-08-12T20:38:16.269Z" }, +] + +[[package]] +name = "charset-normalizer" +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" }, + { url = "https://files.pythonhosted.org/packages/df/68/a576b31b694d07b53807269d05ec3f6f1093e9545e8607121995ba7a8313/charset_normalizer-3.4.2-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:28a1005facc94196e1fb3e82a3d442a9d9110b8434fc1ded7a24a2983c9888d8", size = 145657, upload-time = "2025-05-02T08:32:17.283Z" }, + { url = "https://files.pythonhosted.org/packages/92/9b/ad67f03d74554bed3aefd56fe836e1623a50780f7c998d00ca128924a499/charset_normalizer-3.4.2-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:fdb20a30fe1175ecabed17cbf7812f7b804b8a315a25f24678bcdf120a90077f", size = 147260, upload-time = "2025-05-02T08:32:18.807Z" }, + { url = "https://files.pythonhosted.org/packages/a6/e6/8aebae25e328160b20e31a7e9929b1578bbdc7f42e66f46595a432f8539e/charset_normalizer-3.4.2-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:0f5d9ed7f254402c9e7d35d2f5972c9bbea9040e99cd2861bd77dc68263277c7", size = 149164, upload-time = "2025-05-02T08:32:20.333Z" }, + { url = "https://files.pythonhosted.org/packages/8b/f2/b3c2f07dbcc248805f10e67a0262c93308cfa149a4cd3d1fe01f593e5fd2/charset_normalizer-3.4.2-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:efd387a49825780ff861998cd959767800d54f8308936b21025326de4b5a42b9", size = 144571, upload-time = "2025-05-02T08:32:21.86Z" }, + { url = "https://files.pythonhosted.org/packages/60/5b/c3f3a94bc345bc211622ea59b4bed9ae63c00920e2e8f11824aa5708e8b7/charset_normalizer-3.4.2-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:f0aa37f3c979cf2546b73e8222bbfa3dc07a641585340179d768068e3455e544", size = 151952, upload-time = "2025-05-02T08:32:23.434Z" }, + { url = "https://files.pythonhosted.org/packages/e2/4d/ff460c8b474122334c2fa394a3f99a04cf11c646da895f81402ae54f5c42/charset_normalizer-3.4.2-cp311-cp311-musllinux_1_2_ppc64le.whl", hash = "sha256:e70e990b2137b29dc5564715de1e12701815dacc1d056308e2b17e9095372a82", size = 155959, upload-time = "2025-05-02T08:32:24.993Z" }, + { url = "https://files.pythonhosted.org/packages/a2/2b/b964c6a2fda88611a1fe3d4c400d39c66a42d6c169c924818c848f922415/charset_normalizer-3.4.2-cp311-cp311-musllinux_1_2_s390x.whl", hash = "sha256:0c8c57f84ccfc871a48a47321cfa49ae1df56cd1d965a09abe84066f6853b9c0", size = 153030, upload-time = "2025-05-02T08:32:26.435Z" }, + { url = "https://files.pythonhosted.org/packages/59/2e/d3b9811db26a5ebf444bc0fa4f4be5aa6d76fc6e1c0fd537b16c14e849b6/charset_normalizer-3.4.2-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:6b66f92b17849b85cad91259efc341dce9c1af48e2173bf38a85c6329f1033e5", size = 148015, upload-time = "2025-05-02T08:32:28.376Z" }, + { url = "https://files.pythonhosted.org/packages/90/07/c5fd7c11eafd561bb51220d600a788f1c8d77c5eef37ee49454cc5c35575/charset_normalizer-3.4.2-cp311-cp311-win32.whl", hash = "sha256:daac4765328a919a805fa5e2720f3e94767abd632ae410a9062dff5412bae65a", size = 98106, upload-time = "2025-05-02T08:32:30.281Z" }, + { url = "https://files.pythonhosted.org/packages/a8/05/5e33dbef7e2f773d672b6d79f10ec633d4a71cd96db6673625838a4fd532/charset_normalizer-3.4.2-cp311-cp311-win_amd64.whl", hash = "sha256:e53efc7c7cee4c1e70661e2e112ca46a575f90ed9ae3fef200f2a25e954f4b28", size = 105402, upload-time = "2025-05-02T08:32:32.191Z" }, + { url = "https://files.pythonhosted.org/packages/d7/a4/37f4d6035c89cac7930395a35cc0f1b872e652eaafb76a6075943754f095/charset_normalizer-3.4.2-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:0c29de6a1a95f24b9a1aa7aefd27d2487263f00dfd55a77719b530788f75cff7", size = 199936, upload-time = "2025-05-02T08:32:33.712Z" }, + { url = "https://files.pythonhosted.org/packages/ee/8a/1a5e33b73e0d9287274f899d967907cd0bf9c343e651755d9307e0dbf2b3/charset_normalizer-3.4.2-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:cddf7bd982eaa998934a91f69d182aec997c6c468898efe6679af88283b498d3", size = 143790, upload-time = "2025-05-02T08:32:35.768Z" }, + { url = "https://files.pythonhosted.org/packages/66/52/59521f1d8e6ab1482164fa21409c5ef44da3e9f653c13ba71becdd98dec3/charset_normalizer-3.4.2-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:fcbe676a55d7445b22c10967bceaaf0ee69407fbe0ece4d032b6eb8d4565982a", size = 153924, upload-time = "2025-05-02T08:32:37.284Z" }, + { url = "https://files.pythonhosted.org/packages/86/2d/fb55fdf41964ec782febbf33cb64be480a6b8f16ded2dbe8db27a405c09f/charset_normalizer-3.4.2-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:d41c4d287cfc69060fa91cae9683eacffad989f1a10811995fa309df656ec214", size = 146626, upload-time = "2025-05-02T08:32:38.803Z" }, + { url = "https://files.pythonhosted.org/packages/8c/73/6ede2ec59bce19b3edf4209d70004253ec5f4e319f9a2e3f2f15601ed5f7/charset_normalizer-3.4.2-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:4e594135de17ab3866138f496755f302b72157d115086d100c3f19370839dd3a", size = 148567, upload-time = "2025-05-02T08:32:40.251Z" }, + { url = "https://files.pythonhosted.org/packages/09/14/957d03c6dc343c04904530b6bef4e5efae5ec7d7990a7cbb868e4595ee30/charset_normalizer-3.4.2-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:cf713fe9a71ef6fd5adf7a79670135081cd4431c2943864757f0fa3a65b1fafd", size = 150957, upload-time = "2025-05-02T08:32:41.705Z" }, + { url = "https://files.pythonhosted.org/packages/0d/c8/8174d0e5c10ccebdcb1b53cc959591c4c722a3ad92461a273e86b9f5a302/charset_normalizer-3.4.2-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:a370b3e078e418187da8c3674eddb9d983ec09445c99a3a263c2011993522981", size = 145408, upload-time = "2025-05-02T08:32:43.709Z" }, + { url = "https://files.pythonhosted.org/packages/58/aa/8904b84bc8084ac19dc52feb4f5952c6df03ffb460a887b42615ee1382e8/charset_normalizer-3.4.2-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:a955b438e62efdf7e0b7b52a64dc5c3396e2634baa62471768a64bc2adb73d5c", size = 153399, upload-time = "2025-05-02T08:32:46.197Z" }, + { url = "https://files.pythonhosted.org/packages/c2/26/89ee1f0e264d201cb65cf054aca6038c03b1a0c6b4ae998070392a3ce605/charset_normalizer-3.4.2-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:7222ffd5e4de8e57e03ce2cef95a4c43c98fcb72ad86909abdfc2c17d227fc1b", size = 156815, upload-time = "2025-05-02T08:32:48.105Z" }, + { url = "https://files.pythonhosted.org/packages/fd/07/68e95b4b345bad3dbbd3a8681737b4338ff2c9df29856a6d6d23ac4c73cb/charset_normalizer-3.4.2-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:bee093bf902e1d8fc0ac143c88902c3dfc8941f7ea1d6a8dd2bcb786d33db03d", size = 154537, upload-time = "2025-05-02T08:32:49.719Z" }, + { url = "https://files.pythonhosted.org/packages/77/1a/5eefc0ce04affb98af07bc05f3bac9094513c0e23b0562d64af46a06aae4/charset_normalizer-3.4.2-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:dedb8adb91d11846ee08bec4c8236c8549ac721c245678282dcb06b221aab59f", size = 149565, upload-time = "2025-05-02T08:32:51.404Z" }, + { url = "https://files.pythonhosted.org/packages/37/a0/2410e5e6032a174c95e0806b1a6585eb21e12f445ebe239fac441995226a/charset_normalizer-3.4.2-cp312-cp312-win32.whl", hash = "sha256:db4c7bf0e07fc3b7d89ac2a5880a6a8062056801b83ff56d8464b70f65482b6c", size = 98357, upload-time = "2025-05-02T08:32:53.079Z" }, + { url = "https://files.pythonhosted.org/packages/6c/4f/c02d5c493967af3eda9c771ad4d2bbc8df6f99ddbeb37ceea6e8716a32bc/charset_normalizer-3.4.2-cp312-cp312-win_amd64.whl", hash = "sha256:5a9979887252a82fefd3d3ed2a8e3b937a7a809f65dcb1e068b090e165bbe99e", size = 105776, upload-time = "2025-05-02T08:32:54.573Z" }, + { url = "https://files.pythonhosted.org/packages/ea/12/a93df3366ed32db1d907d7593a94f1fe6293903e3e92967bebd6950ed12c/charset_normalizer-3.4.2-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:926ca93accd5d36ccdabd803392ddc3e03e6d4cd1cf17deff3b989ab8e9dbcf0", size = 199622, upload-time = "2025-05-02T08:32:56.363Z" }, + { url = "https://files.pythonhosted.org/packages/04/93/bf204e6f344c39d9937d3c13c8cd5bbfc266472e51fc8c07cb7f64fcd2de/charset_normalizer-3.4.2-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:eba9904b0f38a143592d9fc0e19e2df0fa2e41c3c3745554761c5f6447eedabf", size = 143435, upload-time = "2025-05-02T08:32:58.551Z" }, + { url = "https://files.pythonhosted.org/packages/22/2a/ea8a2095b0bafa6c5b5a55ffdc2f924455233ee7b91c69b7edfcc9e02284/charset_normalizer-3.4.2-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:3fddb7e2c84ac87ac3a947cb4e66d143ca5863ef48e4a5ecb83bd48619e4634e", size = 153653, upload-time = "2025-05-02T08:33:00.342Z" }, + { url = "https://files.pythonhosted.org/packages/b6/57/1b090ff183d13cef485dfbe272e2fe57622a76694061353c59da52c9a659/charset_normalizer-3.4.2-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:98f862da73774290f251b9df8d11161b6cf25b599a66baf087c1ffe340e9bfd1", size = 146231, upload-time = "2025-05-02T08:33:02.081Z" }, + { url = "https://files.pythonhosted.org/packages/e2/28/ffc026b26f441fc67bd21ab7f03b313ab3fe46714a14b516f931abe1a2d8/charset_normalizer-3.4.2-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6c9379d65defcab82d07b2a9dfbfc2e95bc8fe0ebb1b176a3190230a3ef0e07c", size = 148243, upload-time = "2025-05-02T08:33:04.063Z" }, + { url = "https://files.pythonhosted.org/packages/c0/0f/9abe9bd191629c33e69e47c6ef45ef99773320e9ad8e9cb08b8ab4a8d4cb/charset_normalizer-3.4.2-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:e635b87f01ebc977342e2697d05b56632f5f879a4f15955dfe8cef2448b51691", size = 150442, upload-time = "2025-05-02T08:33:06.418Z" }, + { url = "https://files.pythonhosted.org/packages/67/7c/a123bbcedca91d5916c056407f89a7f5e8fdfce12ba825d7d6b9954a1a3c/charset_normalizer-3.4.2-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:1c95a1e2902a8b722868587c0e1184ad5c55631de5afc0eb96bc4b0d738092c0", size = 145147, upload-time = "2025-05-02T08:33:08.183Z" }, + { url = "https://files.pythonhosted.org/packages/ec/fe/1ac556fa4899d967b83e9893788e86b6af4d83e4726511eaaad035e36595/charset_normalizer-3.4.2-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:ef8de666d6179b009dce7bcb2ad4c4a779f113f12caf8dc77f0162c29d20490b", size = 153057, upload-time = "2025-05-02T08:33:09.986Z" }, + { url = "https://files.pythonhosted.org/packages/2b/ff/acfc0b0a70b19e3e54febdd5301a98b72fa07635e56f24f60502e954c461/charset_normalizer-3.4.2-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:32fc0341d72e0f73f80acb0a2c94216bd704f4f0bce10aedea38f30502b271ff", size = 156454, upload-time = "2025-05-02T08:33:11.814Z" }, + { url = "https://files.pythonhosted.org/packages/92/08/95b458ce9c740d0645feb0e96cea1f5ec946ea9c580a94adfe0b617f3573/charset_normalizer-3.4.2-cp313-cp313-musllinux_1_2_s390x.whl", hash = "sha256:289200a18fa698949d2b39c671c2cc7a24d44096784e76614899a7ccf2574b7b", size = 154174, upload-time = "2025-05-02T08:33:13.707Z" }, + { url = "https://files.pythonhosted.org/packages/78/be/8392efc43487ac051eee6c36d5fbd63032d78f7728cb37aebcc98191f1ff/charset_normalizer-3.4.2-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:4a476b06fbcf359ad25d34a057b7219281286ae2477cc5ff5e3f70a246971148", size = 149166, upload-time = "2025-05-02T08:33:15.458Z" }, + { url = "https://files.pythonhosted.org/packages/44/96/392abd49b094d30b91d9fbda6a69519e95802250b777841cf3bda8fe136c/charset_normalizer-3.4.2-cp313-cp313-win32.whl", hash = "sha256:aaeeb6a479c7667fbe1099af9617c83aaca22182d6cf8c53966491a0f1b7ffb7", size = 98064, upload-time = "2025-05-02T08:33:17.06Z" }, + { url = "https://files.pythonhosted.org/packages/e9/b0/0200da600134e001d91851ddc797809e2fe0ea72de90e09bec5a2fbdaccb/charset_normalizer-3.4.2-cp313-cp313-win_amd64.whl", hash = "sha256:aa6af9e7d59f9c12b33ae4e9450619cf2488e2bbe9b44030905877f0b2324980", size = 105641, upload-time = "2025-05-02T08:33:18.753Z" }, + { 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 = "colorama" +version = "0.4.6" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/d8/53/6f443c9a4a8358a93a6792e2acffb9d9d5cb0a5cfd8802644b7b1c9a02e4/colorama-0.4.6.tar.gz", hash = "sha256:08695f5cb7ed6e0531a20572697297273c47b8cae5a63ffc6d6ed5c201be6e44", size = 27697, upload-time = "2022-10-25T02:36:22.414Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/d1/d6/3965ed04c63042e047cb6a3e6ed1a63a35087b6a609aa3a15ed8ac56c221/colorama-0.4.6-py2.py3-none-any.whl", hash = "sha256:4f1d9991f5acc0ca119f9d443620b77f9d6b33703e51011c16baf57afb285fc6", size = 25335, upload-time = "2022-10-25T02:36:20.889Z" }, +] + +[[package]] +name = "contourpy" +version = "1.3.2" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "numpy", version = "2.2.6", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version < '3.11'" }, + { name = "numpy", version = "2.3.0", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.11'" }, +] +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" }, + { url = "https://files.pythonhosted.org/packages/c3/a6/8ccf97a50f31adfa36917707fe39c9a0cbc24b3bbb58185577f119736cc9/contourpy-1.3.2-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:70771a461aaeb335df14deb6c97439973d253ae70660ca085eec25241137ef43", size = 352985, upload-time = "2025-04-15T17:36:08.275Z" }, + { url = "https://files.pythonhosted.org/packages/1d/b6/7925ab9b77386143f39d9c3243fdd101621b4532eb126743201160ffa7e6/contourpy-1.3.2-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:65a887a6e8c4cd0897507d814b14c54a8c2e2aa4ac9f7686292f9769fcf9a6ab", size = 323750, upload-time = "2025-04-15T17:36:13.29Z" }, + { url = "https://files.pythonhosted.org/packages/c2/f3/20c5d1ef4f4748e52d60771b8560cf00b69d5c6368b5c2e9311bcfa2a08b/contourpy-1.3.2-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3859783aefa2b8355697f16642695a5b9792e7a46ab86da1118a4a23a51a33d7", size = 326246, upload-time = "2025-04-15T17:36:18.329Z" }, + { url = "https://files.pythonhosted.org/packages/8c/e5/9dae809e7e0b2d9d70c52b3d24cba134dd3dad979eb3e5e71f5df22ed1f5/contourpy-1.3.2-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:eab0f6db315fa4d70f1d8ab514e527f0366ec021ff853d7ed6a2d33605cf4b83", size = 1308728, upload-time = "2025-04-15T17:36:33.878Z" }, + { url = "https://files.pythonhosted.org/packages/e2/4a/0058ba34aeea35c0b442ae61a4f4d4ca84d6df8f91309bc2d43bb8dd248f/contourpy-1.3.2-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:d91a3ccc7fea94ca0acab82ceb77f396d50a1f67412efe4c526f5d20264e6ecd", size = 1375762, upload-time = "2025-04-15T17:36:51.295Z" }, + { url = "https://files.pythonhosted.org/packages/09/33/7174bdfc8b7767ef2c08ed81244762d93d5c579336fc0b51ca57b33d1b80/contourpy-1.3.2-cp311-cp311-win32.whl", hash = "sha256:1c48188778d4d2f3d48e4643fb15d8608b1d01e4b4d6b0548d9b336c28fc9b6f", size = 178196, upload-time = "2025-04-15T17:36:55.002Z" }, + { url = "https://files.pythonhosted.org/packages/5e/fe/4029038b4e1c4485cef18e480b0e2cd2d755448bb071eb9977caac80b77b/contourpy-1.3.2-cp311-cp311-win_amd64.whl", hash = "sha256:5ebac872ba09cb8f2131c46b8739a7ff71de28a24c869bcad554477eb089a878", size = 222017, upload-time = "2025-04-15T17:36:58.576Z" }, + { url = "https://files.pythonhosted.org/packages/34/f7/44785876384eff370c251d58fd65f6ad7f39adce4a093c934d4a67a7c6b6/contourpy-1.3.2-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:4caf2bcd2969402bf77edc4cb6034c7dd7c0803213b3523f111eb7460a51b8d2", size = 271580, upload-time = "2025-04-15T17:37:03.105Z" }, + { url = "https://files.pythonhosted.org/packages/93/3b/0004767622a9826ea3d95f0e9d98cd8729015768075d61f9fea8eeca42a8/contourpy-1.3.2-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:82199cb78276249796419fe36b7386bd8d2cc3f28b3bc19fe2454fe2e26c4c15", size = 255530, upload-time = "2025-04-15T17:37:07.026Z" }, + { url = "https://files.pythonhosted.org/packages/e7/bb/7bd49e1f4fa805772d9fd130e0d375554ebc771ed7172f48dfcd4ca61549/contourpy-1.3.2-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:106fab697af11456fcba3e352ad50effe493a90f893fca6c2ca5c033820cea92", size = 307688, upload-time = "2025-04-15T17:37:11.481Z" }, + { url = "https://files.pythonhosted.org/packages/fc/97/e1d5dbbfa170725ef78357a9a0edc996b09ae4af170927ba8ce977e60a5f/contourpy-1.3.2-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:d14f12932a8d620e307f715857107b1d1845cc44fdb5da2bc8e850f5ceba9f87", size = 347331, upload-time = "2025-04-15T17:37:18.212Z" }, + { url = "https://files.pythonhosted.org/packages/6f/66/e69e6e904f5ecf6901be3dd16e7e54d41b6ec6ae3405a535286d4418ffb4/contourpy-1.3.2-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:532fd26e715560721bb0d5fc7610fce279b3699b018600ab999d1be895b09415", size = 318963, upload-time = "2025-04-15T17:37:22.76Z" }, + { url = "https://files.pythonhosted.org/packages/a8/32/b8a1c8965e4f72482ff2d1ac2cd670ce0b542f203c8e1d34e7c3e6925da7/contourpy-1.3.2-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f26b383144cf2d2c29f01a1e8170f50dacf0eac02d64139dcd709a8ac4eb3cfe", size = 323681, upload-time = "2025-04-15T17:37:33.001Z" }, + { url = "https://files.pythonhosted.org/packages/30/c6/12a7e6811d08757c7162a541ca4c5c6a34c0f4e98ef2b338791093518e40/contourpy-1.3.2-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:c49f73e61f1f774650a55d221803b101d966ca0c5a2d6d5e4320ec3997489441", size = 1308674, upload-time = "2025-04-15T17:37:48.64Z" }, + { url = "https://files.pythonhosted.org/packages/2a/8a/bebe5a3f68b484d3a2b8ffaf84704b3e343ef1addea528132ef148e22b3b/contourpy-1.3.2-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:3d80b2c0300583228ac98d0a927a1ba6a2ba6b8a742463c564f1d419ee5b211e", size = 1380480, upload-time = "2025-04-15T17:38:06.7Z" }, + { url = "https://files.pythonhosted.org/packages/34/db/fcd325f19b5978fb509a7d55e06d99f5f856294c1991097534360b307cf1/contourpy-1.3.2-cp312-cp312-win32.whl", hash = "sha256:90df94c89a91b7362e1142cbee7568f86514412ab8a2c0d0fca72d7e91b62912", size = 178489, upload-time = "2025-04-15T17:38:10.338Z" }, + { url = "https://files.pythonhosted.org/packages/01/c8/fadd0b92ffa7b5eb5949bf340a63a4a496a6930a6c37a7ba0f12acb076d6/contourpy-1.3.2-cp312-cp312-win_amd64.whl", hash = "sha256:8c942a01d9163e2e5cfb05cb66110121b8d07ad438a17f9e766317bcb62abf73", size = 223042, upload-time = "2025-04-15T17:38:14.239Z" }, + { url = "https://files.pythonhosted.org/packages/2e/61/5673f7e364b31e4e7ef6f61a4b5121c5f170f941895912f773d95270f3a2/contourpy-1.3.2-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:de39db2604ae755316cb5967728f4bea92685884b1e767b7c24e983ef5f771cb", size = 271630, upload-time = "2025-04-15T17:38:19.142Z" }, + { url = "https://files.pythonhosted.org/packages/ff/66/a40badddd1223822c95798c55292844b7e871e50f6bfd9f158cb25e0bd39/contourpy-1.3.2-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:3f9e896f447c5c8618f1edb2bafa9a4030f22a575ec418ad70611450720b5b08", size = 255670, upload-time = "2025-04-15T17:38:23.688Z" }, + { url = "https://files.pythonhosted.org/packages/1e/c7/cf9fdee8200805c9bc3b148f49cb9482a4e3ea2719e772602a425c9b09f8/contourpy-1.3.2-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:71e2bd4a1c4188f5c2b8d274da78faab884b59df20df63c34f74aa1813c4427c", size = 306694, upload-time = "2025-04-15T17:38:28.238Z" }, + { url = "https://files.pythonhosted.org/packages/dd/e7/ccb9bec80e1ba121efbffad7f38021021cda5be87532ec16fd96533bb2e0/contourpy-1.3.2-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:de425af81b6cea33101ae95ece1f696af39446db9682a0b56daaa48cfc29f38f", size = 345986, upload-time = "2025-04-15T17:38:33.502Z" }, + { url = "https://files.pythonhosted.org/packages/dc/49/ca13bb2da90391fa4219fdb23b078d6065ada886658ac7818e5441448b78/contourpy-1.3.2-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:977e98a0e0480d3fe292246417239d2d45435904afd6d7332d8455981c408b85", size = 318060, upload-time = "2025-04-15T17:38:38.672Z" }, + { url = "https://files.pythonhosted.org/packages/c8/65/5245ce8c548a8422236c13ffcdcdada6a2a812c361e9e0c70548bb40b661/contourpy-1.3.2-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:434f0adf84911c924519d2b08fc10491dd282b20bdd3fa8f60fd816ea0b48841", size = 322747, upload-time = "2025-04-15T17:38:43.712Z" }, + { url = "https://files.pythonhosted.org/packages/72/30/669b8eb48e0a01c660ead3752a25b44fdb2e5ebc13a55782f639170772f9/contourpy-1.3.2-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:c66c4906cdbc50e9cba65978823e6e00b45682eb09adbb78c9775b74eb222422", size = 1308895, upload-time = "2025-04-15T17:39:00.224Z" }, + { url = "https://files.pythonhosted.org/packages/05/5a/b569f4250decee6e8d54498be7bdf29021a4c256e77fe8138c8319ef8eb3/contourpy-1.3.2-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:8b7fc0cd78ba2f4695fd0a6ad81a19e7e3ab825c31b577f384aa9d7817dc3bef", size = 1379098, upload-time = "2025-04-15T17:43:29.649Z" }, + { url = "https://files.pythonhosted.org/packages/19/ba/b227c3886d120e60e41b28740ac3617b2f2b971b9f601c835661194579f1/contourpy-1.3.2-cp313-cp313-win32.whl", hash = "sha256:15ce6ab60957ca74cff444fe66d9045c1fd3e92c8936894ebd1f3eef2fff075f", size = 178535, upload-time = "2025-04-15T17:44:44.532Z" }, + { url = "https://files.pythonhosted.org/packages/12/6e/2fed56cd47ca739b43e892707ae9a13790a486a3173be063681ca67d2262/contourpy-1.3.2-cp313-cp313-win_amd64.whl", hash = "sha256:e1578f7eafce927b168752ed7e22646dad6cd9bca673c60bff55889fa236ebf9", size = 223096, upload-time = "2025-04-15T17:44:48.194Z" }, + { url = "https://files.pythonhosted.org/packages/54/4c/e76fe2a03014a7c767d79ea35c86a747e9325537a8b7627e0e5b3ba266b4/contourpy-1.3.2-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:0475b1f6604896bc7c53bb070e355e9321e1bc0d381735421a2d2068ec56531f", size = 285090, upload-time = "2025-04-15T17:43:34.084Z" }, + { url = "https://files.pythonhosted.org/packages/7b/e2/5aba47debd55d668e00baf9651b721e7733975dc9fc27264a62b0dd26eb8/contourpy-1.3.2-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:c85bb486e9be652314bb5b9e2e3b0d1b2e643d5eec4992c0fbe8ac71775da739", size = 268643, upload-time = "2025-04-15T17:43:38.626Z" }, + { url = "https://files.pythonhosted.org/packages/a1/37/cd45f1f051fe6230f751cc5cdd2728bb3a203f5619510ef11e732109593c/contourpy-1.3.2-cp313-cp313t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:745b57db7758f3ffc05a10254edd3182a2a83402a89c00957a8e8a22f5582823", size = 310443, upload-time = "2025-04-15T17:43:44.522Z" }, + { url = "https://files.pythonhosted.org/packages/8b/a2/36ea6140c306c9ff6dd38e3bcec80b3b018474ef4d17eb68ceecd26675f4/contourpy-1.3.2-cp313-cp313t-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:970e9173dbd7eba9b4e01aab19215a48ee5dd3f43cef736eebde064a171f89a5", size = 349865, upload-time = "2025-04-15T17:43:49.545Z" }, + { url = "https://files.pythonhosted.org/packages/95/b7/2fc76bc539693180488f7b6cc518da7acbbb9e3b931fd9280504128bf956/contourpy-1.3.2-cp313-cp313t-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:c6c4639a9c22230276b7bffb6a850dfc8258a2521305e1faefe804d006b2e532", size = 321162, upload-time = "2025-04-15T17:43:54.203Z" }, + { url = "https://files.pythonhosted.org/packages/f4/10/76d4f778458b0aa83f96e59d65ece72a060bacb20cfbee46cf6cd5ceba41/contourpy-1.3.2-cp313-cp313t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:cc829960f34ba36aad4302e78eabf3ef16a3a100863f0d4eeddf30e8a485a03b", size = 327355, upload-time = "2025-04-15T17:44:01.025Z" }, + { url = "https://files.pythonhosted.org/packages/43/a3/10cf483ea683f9f8ab096c24bad3cce20e0d1dd9a4baa0e2093c1c962d9d/contourpy-1.3.2-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:d32530b534e986374fc19eaa77fcb87e8a99e5431499949b828312bdcd20ac52", size = 1307935, upload-time = "2025-04-15T17:44:17.322Z" }, + { 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" }, +] + +[[package]] +name = "cryptography" +version = "45.0.4" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "cffi", marker = "platform_python_implementation != 'PyPy'" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/fe/c8/a2a376a8711c1e11708b9c9972e0c3223f5fc682552c82d8db844393d6ce/cryptography-45.0.4.tar.gz", hash = "sha256:7405ade85c83c37682c8fe65554759800a4a8c54b2d96e0f8ad114d31b808d57", size = 744890, upload-time = "2025-06-10T00:03:51.297Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/ba/14/93b69f2af9ba832ad6618a03f8a034a5851dc9a3314336a3d71c252467e1/cryptography-45.0.4-cp311-abi3-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:680806cf63baa0039b920f4976f5f31b10e772de42f16310a6839d9f21a26b0d", size = 4205335, upload-time = "2025-06-10T00:02:41.64Z" }, + { url = "https://files.pythonhosted.org/packages/67/30/fae1000228634bf0b647fca80403db5ca9e3933b91dd060570689f0bd0f7/cryptography-45.0.4-cp311-abi3-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:4ca0f52170e821bc8da6fc0cc565b7bb8ff8d90d36b5e9fdd68e8a86bdf72036", size = 4431487, upload-time = "2025-06-10T00:02:43.696Z" }, + { url = "https://files.pythonhosted.org/packages/6d/5a/7dffcf8cdf0cb3c2430de7404b327e3db64735747d641fc492539978caeb/cryptography-45.0.4-cp311-abi3-manylinux_2_28_aarch64.whl", hash = "sha256:f3fe7a5ae34d5a414957cc7f457e2b92076e72938423ac64d215722f6cf49a9e", size = 4208922, upload-time = "2025-06-10T00:02:45.334Z" }, + { url = "https://files.pythonhosted.org/packages/c6/f3/528729726eb6c3060fa3637253430547fbaaea95ab0535ea41baa4a6fbd8/cryptography-45.0.4-cp311-abi3-manylinux_2_28_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:25eb4d4d3e54595dc8adebc6bbd5623588991d86591a78c2548ffb64797341e2", size = 3900433, upload-time = "2025-06-10T00:02:47.359Z" }, + { url = "https://files.pythonhosted.org/packages/d9/4a/67ba2e40f619e04d83c32f7e1d484c1538c0800a17c56a22ff07d092ccc1/cryptography-45.0.4-cp311-abi3-manylinux_2_28_x86_64.whl", hash = "sha256:ce1678a2ccbe696cf3af15a75bb72ee008d7ff183c9228592ede9db467e64f1b", size = 4464163, upload-time = "2025-06-10T00:02:49.412Z" }, + { url = "https://files.pythonhosted.org/packages/7e/9a/b4d5aa83661483ac372464809c4b49b5022dbfe36b12fe9e323ca8512420/cryptography-45.0.4-cp311-abi3-manylinux_2_34_aarch64.whl", hash = "sha256:49fe9155ab32721b9122975e168a6760d8ce4cffe423bcd7ca269ba41b5dfac1", size = 4208687, upload-time = "2025-06-10T00:02:50.976Z" }, + { url = "https://files.pythonhosted.org/packages/db/b7/a84bdcd19d9c02ec5807f2ec2d1456fd8451592c5ee353816c09250e3561/cryptography-45.0.4-cp311-abi3-manylinux_2_34_x86_64.whl", hash = "sha256:2882338b2a6e0bd337052e8b9007ced85c637da19ef9ecaf437744495c8c2999", size = 4463623, upload-time = "2025-06-10T00:02:52.542Z" }, + { url = "https://files.pythonhosted.org/packages/d8/84/69707d502d4d905021cac3fb59a316344e9f078b1da7fb43ecde5e10840a/cryptography-45.0.4-cp311-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:23b9c3ea30c3ed4db59e7b9619272e94891f8a3a5591d0b656a7582631ccf750", size = 4332447, upload-time = "2025-06-10T00:02:54.63Z" }, + { url = "https://files.pythonhosted.org/packages/f3/ee/d4f2ab688e057e90ded24384e34838086a9b09963389a5ba6854b5876598/cryptography-45.0.4-cp311-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:b0a97c927497e3bc36b33987abb99bf17a9a175a19af38a892dc4bbb844d7ee2", size = 4572830, upload-time = "2025-06-10T00:02:56.689Z" }, + { url = "https://files.pythonhosted.org/packages/fe/51/8c584ed426093aac257462ae62d26ad61ef1cbf5b58d8b67e6e13c39960e/cryptography-45.0.4-cp37-abi3-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:6a5bf57554e80f75a7db3d4b1dacaa2764611ae166ab42ea9a72bcdb5d577637", size = 4195746, upload-time = "2025-06-10T00:03:03.94Z" }, + { url = "https://files.pythonhosted.org/packages/5c/7d/4b0ca4d7af95a704eef2f8f80a8199ed236aaf185d55385ae1d1610c03c2/cryptography-45.0.4-cp37-abi3-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:46cf7088bf91bdc9b26f9c55636492c1cce3e7aaf8041bbf0243f5e5325cfb2d", size = 4424456, upload-time = "2025-06-10T00:03:05.589Z" }, + { url = "https://files.pythonhosted.org/packages/1d/45/5fabacbc6e76ff056f84d9f60eeac18819badf0cefc1b6612ee03d4ab678/cryptography-45.0.4-cp37-abi3-manylinux_2_28_aarch64.whl", hash = "sha256:7bedbe4cc930fa4b100fc845ea1ea5788fcd7ae9562e669989c11618ae8d76ee", size = 4198495, upload-time = "2025-06-10T00:03:09.172Z" }, + { url = "https://files.pythonhosted.org/packages/55/b7/ffc9945b290eb0a5d4dab9b7636706e3b5b92f14ee5d9d4449409d010d54/cryptography-45.0.4-cp37-abi3-manylinux_2_28_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:eaa3e28ea2235b33220b949c5a0d6cf79baa80eab2eb5607ca8ab7525331b9ff", size = 3885540, upload-time = "2025-06-10T00:03:10.835Z" }, + { url = "https://files.pythonhosted.org/packages/7f/e3/57b010282346980475e77d414080acdcb3dab9a0be63071efc2041a2c6bd/cryptography-45.0.4-cp37-abi3-manylinux_2_28_x86_64.whl", hash = "sha256:7ef2dde4fa9408475038fc9aadfc1fb2676b174e68356359632e980c661ec8f6", size = 4452052, upload-time = "2025-06-10T00:03:12.448Z" }, + { url = "https://files.pythonhosted.org/packages/37/e6/ddc4ac2558bf2ef517a358df26f45bc774a99bf4653e7ee34b5e749c03e3/cryptography-45.0.4-cp37-abi3-manylinux_2_34_aarch64.whl", hash = "sha256:6a3511ae33f09094185d111160fd192c67aa0a2a8d19b54d36e4c78f651dc5ad", size = 4198024, upload-time = "2025-06-10T00:03:13.976Z" }, + { url = "https://files.pythonhosted.org/packages/3a/c0/85fa358ddb063ec588aed4a6ea1df57dc3e3bc1712d87c8fa162d02a65fc/cryptography-45.0.4-cp37-abi3-manylinux_2_34_x86_64.whl", hash = "sha256:06509dc70dd71fa56eaa138336244e2fbaf2ac164fc9b5e66828fccfd2b680d6", size = 4451442, upload-time = "2025-06-10T00:03:16.248Z" }, + { url = "https://files.pythonhosted.org/packages/33/67/362d6ec1492596e73da24e669a7fbbaeb1c428d6bf49a29f7a12acffd5dc/cryptography-45.0.4-cp37-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:5f31e6b0a5a253f6aa49be67279be4a7e5a4ef259a9f33c69f7d1b1191939872", size = 4325038, upload-time = "2025-06-10T00:03:18.4Z" }, + { url = "https://files.pythonhosted.org/packages/53/75/82a14bf047a96a1b13ebb47fb9811c4f73096cfa2e2b17c86879687f9027/cryptography-45.0.4-cp37-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:944e9ccf67a9594137f942d5b52c8d238b1b4e46c7a0c2891b7ae6e01e7c80a4", size = 4560964, upload-time = "2025-06-10T00:03:20.06Z" }, + { url = "https://files.pythonhosted.org/packages/c4/b9/357f18064ec09d4807800d05a48f92f3b369056a12f995ff79549fbb31f1/cryptography-45.0.4-pp310-pypy310_pp73-manylinux_2_28_aarch64.whl", hash = "sha256:7aad98a25ed8ac917fdd8a9c1e706e5a0956e06c498be1f713b61734333a4507", size = 4143732, upload-time = "2025-06-10T00:03:27.896Z" }, + { url = "https://files.pythonhosted.org/packages/c4/9c/7f7263b03d5db329093617648b9bd55c953de0b245e64e866e560f9aac07/cryptography-45.0.4-pp310-pypy310_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:3530382a43a0e524bc931f187fc69ef4c42828cf7d7f592f7f249f602b5a4ab0", size = 4385424, upload-time = "2025-06-10T00:03:29.992Z" }, + { url = "https://files.pythonhosted.org/packages/a6/5a/6aa9d8d5073d5acc0e04e95b2860ef2684b2bd2899d8795fc443013e263b/cryptography-45.0.4-pp310-pypy310_pp73-manylinux_2_34_aarch64.whl", hash = "sha256:6b613164cb8425e2f8db5849ffb84892e523bf6d26deb8f9bb76ae86181fa12b", size = 4142438, upload-time = "2025-06-10T00:03:31.782Z" }, + { url = "https://files.pythonhosted.org/packages/42/1c/71c638420f2cdd96d9c2b287fec515faf48679b33a2b583d0f1eda3a3375/cryptography-45.0.4-pp310-pypy310_pp73-manylinux_2_34_x86_64.whl", hash = "sha256:96d4819e25bf3b685199b304a0029ce4a3caf98947ce8a066c9137cc78ad2c58", size = 4384622, upload-time = "2025-06-10T00:03:33.491Z" }, + { url = "https://files.pythonhosted.org/packages/28/9a/a7d5bb87d149eb99a5abdc69a41e4e47b8001d767e5f403f78bfaafc7aa7/cryptography-45.0.4-pp311-pypy311_pp73-manylinux_2_28_aarch64.whl", hash = "sha256:03dbff8411206713185b8cebe31bc5c0eb544799a50c09035733716b386e61a4", size = 4146899, upload-time = "2025-06-10T00:03:38.659Z" }, + { url = "https://files.pythonhosted.org/packages/17/11/9361c2c71c42cc5c465cf294c8030e72fb0c87752bacbd7a3675245e3db3/cryptography-45.0.4-pp311-pypy311_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:51dfbd4d26172d31150d84c19bbe06c68ea4b7f11bbc7b3a5e146b367c311349", size = 4388900, upload-time = "2025-06-10T00:03:40.233Z" }, + { url = "https://files.pythonhosted.org/packages/c0/76/f95b83359012ee0e670da3e41c164a0c256aeedd81886f878911581d852f/cryptography-45.0.4-pp311-pypy311_pp73-manylinux_2_34_aarch64.whl", hash = "sha256:0339a692de47084969500ee455e42c58e449461e0ec845a34a6a9b9bf7df7fb8", size = 4146422, upload-time = "2025-06-10T00:03:41.827Z" }, + { url = "https://files.pythonhosted.org/packages/09/ad/5429fcc4def93e577a5407988f89cf15305e64920203d4ac14601a9dc876/cryptography-45.0.4-pp311-pypy311_pp73-manylinux_2_34_x86_64.whl", hash = "sha256:0cf13c77d710131d33e63626bd55ae7c0efb701ebdc2b3a7952b9b23a0412862", size = 4388475, upload-time = "2025-06-10T00:03:43.493Z" }, +] + +[[package]] +name = "cycler" +version = "0.12.1" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/a9/95/a3dbbb5028f35eafb79008e7522a75244477d2838f38cbb722248dabc2a8/cycler-0.12.1.tar.gz", hash = "sha256:88bb128f02ba341da8ef447245a9e138fae777f6a23943da4540077d3601eb1c", size = 7615, upload-time = "2023-10-07T05:32:18.335Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/e7/05/c19819d5e3d95294a6f5947fb9b9629efb316b96de511b418c53d245aae6/cycler-0.12.1-py3-none-any.whl", hash = "sha256:85cef7cff222d8644161529808465972e51340599459b8ac3ccbac5a854e0d30", size = 8321, upload-time = "2023-10-07T05:32:16.783Z" }, +] + +[[package]] +name = "distlib" +version = "0.3.9" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/0d/dd/1bec4c5ddb504ca60fc29472f3d27e8d4da1257a854e1d96742f15c1d02d/distlib-0.3.9.tar.gz", hash = "sha256:a60f20dea646b8a33f3e7772f74dc0b2d0772d2837ee1342a00645c81edf9403", size = 613923, upload-time = "2024-10-09T18:35:47.551Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/91/a1/cf2472db20f7ce4a6be1253a81cfdf85ad9c7885ffbed7047fb72c24cf87/distlib-0.3.9-py2.py3-none-any.whl", hash = "sha256:47f8c22fd27c27e25a65601af709b38e4f0a45ea4fc2e710f65755fa8caaaf87", size = 468973, upload-time = "2024-10-09T18:35:44.272Z" }, +] + +[[package]] +name = "filelock" +version = "3.18.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/0a/10/c23352565a6544bdc5353e0b15fc1c563352101f30e24bf500207a54df9a/filelock-3.18.0.tar.gz", hash = "sha256:adbc88eabb99d2fec8c9c1b229b171f18afa655400173ddc653d5d01501fb9f2", size = 18075, upload-time = "2025-03-14T07:11:40.47Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/4d/36/2a115987e2d8c300a974597416d9de88f2444426de9571f4b59b2cca3acc/filelock-3.18.0-py3-none-any.whl", hash = "sha256:c401f4f8377c4464e6db25fff06205fd89bdd83b65eb0488ed1b160f780e21de", size = 16215, upload-time = "2025-03-14T07:11:39.145Z" }, +] + +[[package]] +name = "fonttools" +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" }, + { url = "https://files.pythonhosted.org/packages/19/48/8322cf177680505d6b0b6062e204f01860cb573466a88077a9b795cb70e8/fonttools-4.58.4-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:891c5771e8f0094b7c0dc90eda8fc75e72930b32581418f2c285a9feedfd9a68", size = 4960922, upload-time = "2025-06-13T17:24:14.9Z" }, + { url = "https://files.pythonhosted.org/packages/14/e0/2aff149ed7eb0916de36da513d473c6fff574a7146891ce42de914899395/fonttools-4.58.4-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:43ba4d9646045c375d22e3473b7d82b18b31ee2ac715cd94220ffab7bc2d5c1d", size = 4997135, upload-time = "2025-06-13T17:24:16.959Z" }, + { url = "https://files.pythonhosted.org/packages/e6/6f/4d9829b29a64a2e63a121cb11ecb1b6a9524086eef3e35470949837a1692/fonttools-4.58.4-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:33d19f16e6d2ffd6669bda574a6589941f6c99a8d5cfb9f464038244c71555de", size = 5108701, upload-time = "2025-06-13T17:24:18.849Z" }, + { url = "https://files.pythonhosted.org/packages/6f/1e/2d656ddd1b0cd0d222f44b2d008052c2689e66b702b9af1cd8903ddce319/fonttools-4.58.4-cp311-cp311-win32.whl", hash = "sha256:b59e5109b907da19dc9df1287454821a34a75f2632a491dd406e46ff432c2a24", size = 2200177, upload-time = "2025-06-13T17:24:20.823Z" }, + { url = "https://files.pythonhosted.org/packages/fb/83/ba71ad053fddf4157cb0697c8da8eff6718d059f2a22986fa5f312b49c92/fonttools-4.58.4-cp311-cp311-win_amd64.whl", hash = "sha256:3d471a5b567a0d1648f2e148c9a8bcf00d9ac76eb89e976d9976582044cc2509", size = 2247892, upload-time = "2025-06-13T17:24:22.927Z" }, + { url = "https://files.pythonhosted.org/packages/04/3c/1d1792bfe91ef46f22a3d23b4deb514c325e73c17d4f196b385b5e2faf1c/fonttools-4.58.4-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:462211c0f37a278494e74267a994f6be9a2023d0557aaa9ecbcbfce0f403b5a6", size = 2754082, upload-time = "2025-06-13T17:24:24.862Z" }, + { url = "https://files.pythonhosted.org/packages/2a/1f/2b261689c901a1c3bc57a6690b0b9fc21a9a93a8b0c83aae911d3149f34e/fonttools-4.58.4-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:0c7a12fb6f769165547f00fcaa8d0df9517603ae7e04b625e5acb8639809b82d", size = 2321677, upload-time = "2025-06-13T17:24:26.815Z" }, + { url = "https://files.pythonhosted.org/packages/fe/6b/4607add1755a1e6581ae1fc0c9a640648e0d9cdd6591cc2d581c2e07b8c3/fonttools-4.58.4-cp312-cp312-manylinux1_x86_64.manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:2d42c63020a922154add0a326388a60a55504629edc3274bc273cd3806b4659f", size = 4896354, upload-time = "2025-06-13T17:24:28.428Z" }, + { url = "https://files.pythonhosted.org/packages/cd/95/34b4f483643d0cb11a1f830b72c03fdd18dbd3792d77a2eb2e130a96fada/fonttools-4.58.4-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:8f2b4e6fd45edc6805f5f2c355590b092ffc7e10a945bd6a569fc66c1d2ae7aa", size = 4941633, upload-time = "2025-06-13T17:24:30.568Z" }, + { url = "https://files.pythonhosted.org/packages/81/ac/9bafbdb7694059c960de523e643fa5a61dd2f698f3f72c0ca18ae99257c7/fonttools-4.58.4-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:f155b927f6efb1213a79334e4cb9904d1e18973376ffc17a0d7cd43d31981f1e", size = 4886170, upload-time = "2025-06-13T17:24:32.724Z" }, + { url = "https://files.pythonhosted.org/packages/ae/44/a3a3b70d5709405f7525bb7cb497b4e46151e0c02e3c8a0e40e5e9fe030b/fonttools-4.58.4-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:e38f687d5de97c7fb7da3e58169fb5ba349e464e141f83c3c2e2beb91d317816", size = 5037851, upload-time = "2025-06-13T17:24:35.034Z" }, + { url = "https://files.pythonhosted.org/packages/21/cb/e8923d197c78969454eb876a4a55a07b59c9c4c46598f02b02411dc3b45c/fonttools-4.58.4-cp312-cp312-win32.whl", hash = "sha256:636c073b4da9db053aa683db99580cac0f7c213a953b678f69acbca3443c12cc", size = 2187428, upload-time = "2025-06-13T17:24:36.996Z" }, + { url = "https://files.pythonhosted.org/packages/46/e6/fe50183b1a0e1018e7487ee740fa8bb127b9f5075a41e20d017201e8ab14/fonttools-4.58.4-cp312-cp312-win_amd64.whl", hash = "sha256:82e8470535743409b30913ba2822e20077acf9ea70acec40b10fcf5671dceb58", size = 2236649, upload-time = "2025-06-13T17:24:38.985Z" }, + { url = "https://files.pythonhosted.org/packages/d4/4f/c05cab5fc1a4293e6bc535c6cb272607155a0517700f5418a4165b7f9ec8/fonttools-4.58.4-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:5f4a64846495c543796fa59b90b7a7a9dff6839bd852741ab35a71994d685c6d", size = 2745197, upload-time = "2025-06-13T17:24:40.645Z" }, + { url = "https://files.pythonhosted.org/packages/3e/d3/49211b1f96ae49308f4f78ca7664742377a6867f00f704cdb31b57e4b432/fonttools-4.58.4-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:e80661793a5d4d7ad132a2aa1eae2e160fbdbb50831a0edf37c7c63b2ed36574", size = 2317272, upload-time = "2025-06-13T17:24:43.428Z" }, + { url = "https://files.pythonhosted.org/packages/b2/11/c9972e46a6abd752a40a46960e431c795ad1f306775fc1f9e8c3081a1274/fonttools-4.58.4-cp313-cp313-manylinux1_x86_64.manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:fe5807fc64e4ba5130f1974c045a6e8d795f3b7fb6debfa511d1773290dbb76b", size = 4877184, upload-time = "2025-06-13T17:24:45.527Z" }, + { url = "https://files.pythonhosted.org/packages/ea/24/5017c01c9ef8df572cc9eaf9f12be83ad8ed722ff6dc67991d3d752956e4/fonttools-4.58.4-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:b610b9bef841cb8f4b50472494158b1e347d15cad56eac414c722eda695a6cfd", size = 4939445, upload-time = "2025-06-13T17:24:47.647Z" }, + { url = "https://files.pythonhosted.org/packages/79/b0/538cc4d0284b5a8826b4abed93a69db52e358525d4b55c47c8cef3669767/fonttools-4.58.4-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:2daa7f0e213c38f05f054eb5e1730bd0424aebddbeac094489ea1585807dd187", size = 4878800, upload-time = "2025-06-13T17:24:49.766Z" }, + { url = "https://files.pythonhosted.org/packages/5a/9b/a891446b7a8250e65bffceb248508587958a94db467ffd33972723ab86c9/fonttools-4.58.4-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:66cccb6c0b944496b7f26450e9a66e997739c513ffaac728d24930df2fd9d35b", size = 5021259, upload-time = "2025-06-13T17:24:51.754Z" }, + { url = "https://files.pythonhosted.org/packages/17/b2/c4d2872cff3ace3ddd1388bf15b76a1d8d5313f0a61f234e9aed287e674d/fonttools-4.58.4-cp313-cp313-win32.whl", hash = "sha256:94d2aebb5ca59a5107825520fde596e344652c1f18170ef01dacbe48fa60c889", size = 2185824, upload-time = "2025-06-13T17:24:54.324Z" }, + { url = "https://files.pythonhosted.org/packages/98/57/cddf8bcc911d4f47dfca1956c1e3aeeb9f7c9b8e88b2a312fe8c22714e0b/fonttools-4.58.4-cp313-cp313-win_amd64.whl", hash = "sha256:b554bd6e80bba582fd326ddab296e563c20c64dca816d5e30489760e0c41529f", size = 2236382, upload-time = "2025-06-13T17:24:56.291Z" }, + { url = "https://files.pythonhosted.org/packages/0b/2f/c536b5b9bb3c071e91d536a4d11f969e911dbb6b227939f4c5b0bca090df/fonttools-4.58.4-py3-none-any.whl", hash = "sha256:a10ce13a13f26cbb9f37512a4346bb437ad7e002ff6fa966a7ce7ff5ac3528bd", size = 1114660, upload-time = "2025-06-13T17:25:13.321Z" }, +] + +[[package]] +name = "html5lib" +version = "1.1" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "six" }, + { name = "webencodings" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/ac/b6/b55c3f49042f1df3dcd422b7f224f939892ee94f22abcf503a9b7339eaf2/html5lib-1.1.tar.gz", hash = "sha256:b2e5b40261e20f354d198eae92afc10d750afb487ed5e50f9c4eaf07c184146f", size = 272215, upload-time = "2020-06-22T23:32:38.834Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/6c/dd/a834df6482147d48e225a49515aabc28974ad5a4ca3215c18a882565b028/html5lib-1.1-py2.py3-none-any.whl", hash = "sha256:0d78f8fde1c230e99fe37986a60526d7049ed4bf8a9fadbad5f00e22e58e041d", size = 112173, upload-time = "2020-06-22T23:32:36.781Z" }, +] + +[[package]] +name = "identify" +version = "2.6.12" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/a2/88/d193a27416618628a5eea64e3223acd800b40749a96ffb322a9b55a49ed1/identify-2.6.12.tar.gz", hash = "sha256:d8de45749f1efb108badef65ee8386f0f7bb19a7f26185f74de6367bffbaf0e6", size = 99254, upload-time = "2025-05-23T20:37:53.3Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/7a/cd/18f8da995b658420625f7ef13f037be53ae04ec5ad33f9b718240dcfd48c/identify-2.6.12-py2.py3-none-any.whl", hash = "sha256:ad9672d5a72e0d2ff7c5c8809b62dfa60458626352fb0eb7b55e69bdc45334a2", size = 99145, upload-time = "2025-05-23T20:37:51.495Z" }, +] + +[[package]] +name = "idna" +version = "3.10" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/f1/70/7703c29685631f5a7590aa73f1f1d3fa9a380e654b86af429e0934a32f7d/idna-3.10.tar.gz", hash = "sha256:12f65c9b470abda6dc35cf8e63cc574b1c52b11df2c86030af0ac09b01b13ea9", size = 190490, upload-time = "2024-09-15T18:07:39.745Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/76/c6/c88e154df9c4e1a2a66ccf0005a88dfb2650c1dffb6f5ce603dfbd452ce3/idna-3.10-py3-none-any.whl", hash = "sha256:946d195a0d259cbba61165e88e65941f16e9b36ea6ddb97f00452bae8b1287d3", size = 70442, upload-time = "2024-09-15T18:07:37.964Z" }, +] + +[[package]] +name = "importlib-metadata" +version = "8.7.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "zipp" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/76/66/650a33bd90f786193e4de4b3ad86ea60b53c89b669a5c7be931fac31cdb0/importlib_metadata-8.7.0.tar.gz", hash = "sha256:d13b81ad223b890aa16c5471f2ac3056cf76c5f10f82d6f9292f0b415f389000", size = 56641, upload-time = "2025-04-27T15:29:01.736Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/20/b0/36bd937216ec521246249be3bf9855081de4c5e06a0c9b4219dbeda50373/importlib_metadata-8.7.0-py3-none-any.whl", hash = "sha256:e5dd1551894c77868a30651cef00984d50e1002d06942a7101d34870c5f02afd", size = 27656, upload-time = "2025-04-27T15:29:00.214Z" }, +] + +[[package]] +name = "jaraco-classes" +version = "3.4.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "more-itertools" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/06/c0/ed4a27bc5571b99e3cff68f8a9fa5b56ff7df1c2251cc715a652ddd26402/jaraco.classes-3.4.0.tar.gz", hash = "sha256:47a024b51d0239c0dd8c8540c6c7f484be3b8fcf0b2d85c13825780d3b3f3acd", size = 11780, upload-time = "2024-03-31T07:27:36.643Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/7f/66/b15ce62552d84bbfcec9a4873ab79d993a1dd4edb922cbfccae192bd5b5f/jaraco.classes-3.4.0-py3-none-any.whl", hash = "sha256:f662826b6bed8cace05e7ff873ce0f9283b5c924470fe664fff1c2f00f581790", size = 6777, upload-time = "2024-03-31T07:27:34.792Z" }, +] + +[[package]] +name = "jaraco-context" +version = "6.0.1" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "backports-tarfile", marker = "python_full_version < '3.12'" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/df/ad/f3777b81bf0b6e7bc7514a1656d3e637b2e8e15fab2ce3235730b3e7a4e6/jaraco_context-6.0.1.tar.gz", hash = "sha256:9bae4ea555cf0b14938dc0aee7c9f32ed303aa20a3b73e7dc80111628792d1b3", size = 13912, upload-time = "2024-08-20T03:39:27.358Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/ff/db/0c52c4cf5e4bd9f5d7135ec7669a3a767af21b3a308e1ed3674881e52b62/jaraco.context-6.0.1-py3-none-any.whl", hash = "sha256:f797fc481b490edb305122c9181830a3a5b76d84ef6d1aef2fb9b47ab956f9e4", size = 6825, upload-time = "2024-08-20T03:39:25.966Z" }, +] + +[[package]] +name = "jaraco-functools" +version = "4.1.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "more-itertools" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/ab/23/9894b3df5d0a6eb44611c36aec777823fc2e07740dabbd0b810e19594013/jaraco_functools-4.1.0.tar.gz", hash = "sha256:70f7e0e2ae076498e212562325e805204fc092d7b4c17e0e86c959e249701a9d", size = 19159, upload-time = "2024-09-27T19:47:09.122Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/9f/4f/24b319316142c44283d7540e76c7b5a6dbd5db623abd86bb7b3491c21018/jaraco.functools-4.1.0-py3-none-any.whl", hash = "sha256:ad159f13428bc4acbf5541ad6dec511f91573b90fba04df61dafa2a1231cf649", size = 10187, upload-time = "2024-09-27T19:47:07.14Z" }, +] + +[[package]] +name = "jeepney" +version = "0.9.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/7b/6f/357efd7602486741aa73ffc0617fb310a29b588ed0fd69c2399acbb85b0c/jeepney-0.9.0.tar.gz", hash = "sha256:cf0e9e845622b81e4a28df94c40345400256ec608d0e55bb8a3feaa9163f5732", size = 106758, upload-time = "2025-02-27T18:51:01.684Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/b2/a3/e137168c9c44d18eff0376253da9f1e9234d0239e0ee230d2fee6cea8e55/jeepney-0.9.0-py3-none-any.whl", hash = "sha256:97e5714520c16fc0a45695e5365a2e11b81ea79bba796e26f9f1d178cb182683", size = 49010, upload-time = "2025-02-27T18:51:00.104Z" }, +] + +[[package]] +name = "keyring" +version = "25.6.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "importlib-metadata", marker = "python_full_version < '3.12'" }, + { name = "jaraco-classes" }, + { name = "jaraco-context" }, + { name = "jaraco-functools" }, + { name = "jeepney", marker = "sys_platform == 'linux'" }, + { name = "pywin32-ctypes", marker = "sys_platform == 'win32'" }, + { name = "secretstorage", marker = "sys_platform == 'linux'" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/70/09/d904a6e96f76ff214be59e7aa6ef7190008f52a0ab6689760a98de0bf37d/keyring-25.6.0.tar.gz", hash = "sha256:0b39998aa941431eb3d9b0d4b2460bc773b9df6fed7621c2dfb291a7e0187a66", size = 62750, upload-time = "2024-12-25T15:26:45.782Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/d3/32/da7f44bcb1105d3e88a0b74ebdca50c59121d2ddf71c9e34ba47df7f3a56/keyring-25.6.0-py3-none-any.whl", hash = "sha256:552a3f7af126ece7ed5c89753650eec89c7eaae8617d0aa4d9ad2b75111266bd", size = 39085, upload-time = "2024-12-25T15:26:44.377Z" }, +] + +[[package]] +name = "kiwisolver" +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" }, + { url = "https://files.pythonhosted.org/packages/a9/98/1df4089b1ed23d83d410adfdc5947245c753bddfbe06541c4aae330e9e70/kiwisolver-1.4.8-cp311-cp311-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:c5020c83e8553f770cb3b5fc13faac40f17e0b205bd237aebd21d53d733adb03", size = 1343994, upload-time = "2024-12-24T18:28:57.493Z" }, + { url = "https://files.pythonhosted.org/packages/8d/bf/b4b169b050c8421a7c53ea1ea74e4ef9c335ee9013216c558a047f162d20/kiwisolver-1.4.8-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:dace81d28c787956bfbfbbfd72fdcef014f37d9b48830829e488fdb32b49d954", size = 1434804, upload-time = "2024-12-24T18:29:00.077Z" }, + { url = "https://files.pythonhosted.org/packages/66/5a/e13bd341fbcf73325ea60fdc8af752addf75c5079867af2e04cc41f34434/kiwisolver-1.4.8-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:11e1022b524bd48ae56c9b4f9296bce77e15a2e42a502cceba602f804b32bb79", size = 1450690, upload-time = "2024-12-24T18:29:01.401Z" }, + { url = "https://files.pythonhosted.org/packages/9b/4f/5955dcb376ba4a830384cc6fab7d7547bd6759fe75a09564910e9e3bb8ea/kiwisolver-1.4.8-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:3b9b4d2892fefc886f30301cdd80debd8bb01ecdf165a449eb6e78f79f0fabd6", size = 1376839, upload-time = "2024-12-24T18:29:02.685Z" }, + { url = "https://files.pythonhosted.org/packages/3a/97/5edbed69a9d0caa2e4aa616ae7df8127e10f6586940aa683a496c2c280b9/kiwisolver-1.4.8-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3a96c0e790ee875d65e340ab383700e2b4891677b7fcd30a699146f9384a2bb0", size = 1435109, upload-time = "2024-12-24T18:29:04.113Z" }, + { url = "https://files.pythonhosted.org/packages/13/fc/e756382cb64e556af6c1809a1bbb22c141bbc2445049f2da06b420fe52bf/kiwisolver-1.4.8-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:23454ff084b07ac54ca8be535f4174170c1094a4cff78fbae4f73a4bcc0d4dab", size = 2245269, upload-time = "2024-12-24T18:29:05.488Z" }, + { url = "https://files.pythonhosted.org/packages/76/15/e59e45829d7f41c776d138245cabae6515cb4eb44b418f6d4109c478b481/kiwisolver-1.4.8-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:87b287251ad6488e95b4f0b4a79a6d04d3ea35fde6340eb38fbd1ca9cd35bbbc", size = 2393468, upload-time = "2024-12-24T18:29:06.79Z" }, + { url = "https://files.pythonhosted.org/packages/e9/39/483558c2a913ab8384d6e4b66a932406f87c95a6080112433da5ed668559/kiwisolver-1.4.8-cp311-cp311-musllinux_1_2_ppc64le.whl", hash = "sha256:b21dbe165081142b1232a240fc6383fd32cdd877ca6cc89eab93e5f5883e1c25", size = 2355394, upload-time = "2024-12-24T18:29:08.24Z" }, + { url = "https://files.pythonhosted.org/packages/01/aa/efad1fbca6570a161d29224f14b082960c7e08268a133fe5dc0f6906820e/kiwisolver-1.4.8-cp311-cp311-musllinux_1_2_s390x.whl", hash = "sha256:768cade2c2df13db52475bd28d3a3fac8c9eff04b0e9e2fda0f3760f20b3f7fc", size = 2490901, upload-time = "2024-12-24T18:29:09.653Z" }, + { url = "https://files.pythonhosted.org/packages/c9/4f/15988966ba46bcd5ab9d0c8296914436720dd67fca689ae1a75b4ec1c72f/kiwisolver-1.4.8-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:d47cfb2650f0e103d4bf68b0b5804c68da97272c84bb12850d877a95c056bd67", size = 2312306, upload-time = "2024-12-24T18:29:12.644Z" }, + { url = "https://files.pythonhosted.org/packages/2d/27/bdf1c769c83f74d98cbc34483a972f221440703054894a37d174fba8aa68/kiwisolver-1.4.8-cp311-cp311-win_amd64.whl", hash = "sha256:ed33ca2002a779a2e20eeb06aea7721b6e47f2d4b8a8ece979d8ba9e2a167e34", size = 71966, upload-time = "2024-12-24T18:29:14.089Z" }, + { url = "https://files.pythonhosted.org/packages/4a/c9/9642ea855604aeb2968a8e145fc662edf61db7632ad2e4fb92424be6b6c0/kiwisolver-1.4.8-cp311-cp311-win_arm64.whl", hash = "sha256:16523b40aab60426ffdebe33ac374457cf62863e330a90a0383639ce14bf44b2", size = 65311, upload-time = "2024-12-24T18:29:15.892Z" }, + { url = "https://files.pythonhosted.org/packages/fc/aa/cea685c4ab647f349c3bc92d2daf7ae34c8e8cf405a6dcd3a497f58a2ac3/kiwisolver-1.4.8-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:d6af5e8815fd02997cb6ad9bbed0ee1e60014438ee1a5c2444c96f87b8843502", size = 124152, upload-time = "2024-12-24T18:29:16.85Z" }, + { url = "https://files.pythonhosted.org/packages/c5/0b/8db6d2e2452d60d5ebc4ce4b204feeb16176a851fd42462f66ade6808084/kiwisolver-1.4.8-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:bade438f86e21d91e0cf5dd7c0ed00cda0f77c8c1616bd83f9fc157fa6760d31", size = 66555, upload-time = "2024-12-24T18:29:19.146Z" }, + { url = "https://files.pythonhosted.org/packages/60/26/d6a0db6785dd35d3ba5bf2b2df0aedc5af089962c6eb2cbf67a15b81369e/kiwisolver-1.4.8-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:b83dc6769ddbc57613280118fb4ce3cd08899cc3369f7d0e0fab518a7cf37fdb", size = 65067, upload-time = "2024-12-24T18:29:20.096Z" }, + { url = "https://files.pythonhosted.org/packages/c9/ed/1d97f7e3561e09757a196231edccc1bcf59d55ddccefa2afc9c615abd8e0/kiwisolver-1.4.8-cp312-cp312-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:111793b232842991be367ed828076b03d96202c19221b5ebab421ce8bcad016f", size = 1378443, upload-time = "2024-12-24T18:29:22.843Z" }, + { url = "https://files.pythonhosted.org/packages/29/61/39d30b99954e6b46f760e6289c12fede2ab96a254c443639052d1b573fbc/kiwisolver-1.4.8-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:257af1622860e51b1a9d0ce387bf5c2c4f36a90594cb9514f55b074bcc787cfc", size = 1472728, upload-time = "2024-12-24T18:29:24.463Z" }, + { url = "https://files.pythonhosted.org/packages/0c/3e/804163b932f7603ef256e4a715e5843a9600802bb23a68b4e08c8c0ff61d/kiwisolver-1.4.8-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:69b5637c3f316cab1ec1c9a12b8c5f4750a4c4b71af9157645bf32830e39c03a", size = 1478388, upload-time = "2024-12-24T18:29:25.776Z" }, + { url = "https://files.pythonhosted.org/packages/8a/9e/60eaa75169a154700be74f875a4d9961b11ba048bef315fbe89cb6999056/kiwisolver-1.4.8-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:782bb86f245ec18009890e7cb8d13a5ef54dcf2ebe18ed65f795e635a96a1c6a", size = 1413849, upload-time = "2024-12-24T18:29:27.202Z" }, + { url = "https://files.pythonhosted.org/packages/bc/b3/9458adb9472e61a998c8c4d95cfdfec91c73c53a375b30b1428310f923e4/kiwisolver-1.4.8-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:cc978a80a0db3a66d25767b03688f1147a69e6237175c0f4ffffaaedf744055a", size = 1475533, upload-time = "2024-12-24T18:29:28.638Z" }, + { url = "https://files.pythonhosted.org/packages/e4/7a/0a42d9571e35798de80aef4bb43a9b672aa7f8e58643d7bd1950398ffb0a/kiwisolver-1.4.8-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:36dbbfd34838500a31f52c9786990d00150860e46cd5041386f217101350f0d3", size = 2268898, upload-time = "2024-12-24T18:29:30.368Z" }, + { url = "https://files.pythonhosted.org/packages/d9/07/1255dc8d80271400126ed8db35a1795b1a2c098ac3a72645075d06fe5c5d/kiwisolver-1.4.8-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:eaa973f1e05131de5ff3569bbba7f5fd07ea0595d3870ed4a526d486fe57fa1b", size = 2425605, upload-time = "2024-12-24T18:29:33.151Z" }, + { url = "https://files.pythonhosted.org/packages/84/df/5a3b4cf13780ef6f6942df67b138b03b7e79e9f1f08f57c49957d5867f6e/kiwisolver-1.4.8-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:a66f60f8d0c87ab7f59b6fb80e642ebb29fec354a4dfad687ca4092ae69d04f4", size = 2375801, upload-time = "2024-12-24T18:29:34.584Z" }, + { url = "https://files.pythonhosted.org/packages/8f/10/2348d068e8b0f635c8c86892788dac7a6b5c0cb12356620ab575775aad89/kiwisolver-1.4.8-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:858416b7fb777a53f0c59ca08190ce24e9abbd3cffa18886a5781b8e3e26f65d", size = 2520077, upload-time = "2024-12-24T18:29:36.138Z" }, + { url = "https://files.pythonhosted.org/packages/32/d8/014b89fee5d4dce157d814303b0fce4d31385a2af4c41fed194b173b81ac/kiwisolver-1.4.8-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:085940635c62697391baafaaeabdf3dd7a6c3643577dde337f4d66eba021b2b8", size = 2338410, upload-time = "2024-12-24T18:29:39.991Z" }, + { url = "https://files.pythonhosted.org/packages/bd/72/dfff0cc97f2a0776e1c9eb5bef1ddfd45f46246c6533b0191887a427bca5/kiwisolver-1.4.8-cp312-cp312-win_amd64.whl", hash = "sha256:01c3d31902c7db5fb6182832713d3b4122ad9317c2c5877d0539227d96bb2e50", size = 71853, upload-time = "2024-12-24T18:29:42.006Z" }, + { url = "https://files.pythonhosted.org/packages/dc/85/220d13d914485c0948a00f0b9eb419efaf6da81b7d72e88ce2391f7aed8d/kiwisolver-1.4.8-cp312-cp312-win_arm64.whl", hash = "sha256:a3c44cb68861de93f0c4a8175fbaa691f0aa22550c331fefef02b618a9dcb476", size = 65424, upload-time = "2024-12-24T18:29:44.38Z" }, + { url = "https://files.pythonhosted.org/packages/79/b3/e62464a652f4f8cd9006e13d07abad844a47df1e6537f73ddfbf1bc997ec/kiwisolver-1.4.8-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:1c8ceb754339793c24aee1c9fb2485b5b1f5bb1c2c214ff13368431e51fc9a09", size = 124156, upload-time = "2024-12-24T18:29:45.368Z" }, + { url = "https://files.pythonhosted.org/packages/8d/2d/f13d06998b546a2ad4f48607a146e045bbe48030774de29f90bdc573df15/kiwisolver-1.4.8-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:54a62808ac74b5e55a04a408cda6156f986cefbcf0ada13572696b507cc92fa1", size = 66555, upload-time = "2024-12-24T18:29:46.37Z" }, + { url = "https://files.pythonhosted.org/packages/59/e3/b8bd14b0a54998a9fd1e8da591c60998dc003618cb19a3f94cb233ec1511/kiwisolver-1.4.8-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:68269e60ee4929893aad82666821aaacbd455284124817af45c11e50a4b42e3c", size = 65071, upload-time = "2024-12-24T18:29:47.333Z" }, + { url = "https://files.pythonhosted.org/packages/f0/1c/6c86f6d85ffe4d0ce04228d976f00674f1df5dc893bf2dd4f1928748f187/kiwisolver-1.4.8-cp313-cp313-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:34d142fba9c464bc3bbfeff15c96eab0e7310343d6aefb62a79d51421fcc5f1b", size = 1378053, upload-time = "2024-12-24T18:29:49.636Z" }, + { url = "https://files.pythonhosted.org/packages/4e/b9/1c6e9f6dcb103ac5cf87cb695845f5fa71379021500153566d8a8a9fc291/kiwisolver-1.4.8-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:3ddc373e0eef45b59197de815b1b28ef89ae3955e7722cc9710fb91cd77b7f47", size = 1472278, upload-time = "2024-12-24T18:29:51.164Z" }, + { url = "https://files.pythonhosted.org/packages/ee/81/aca1eb176de671f8bda479b11acdc42c132b61a2ac861c883907dde6debb/kiwisolver-1.4.8-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:77e6f57a20b9bd4e1e2cedda4d0b986ebd0216236f0106e55c28aea3d3d69b16", size = 1478139, upload-time = "2024-12-24T18:29:52.594Z" }, + { url = "https://files.pythonhosted.org/packages/49/f4/e081522473671c97b2687d380e9e4c26f748a86363ce5af48b4a28e48d06/kiwisolver-1.4.8-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:08e77738ed7538f036cd1170cbed942ef749137b1311fa2bbe2a7fda2f6bf3cc", size = 1413517, upload-time = "2024-12-24T18:29:53.941Z" }, + { url = "https://files.pythonhosted.org/packages/8f/e9/6a7d025d8da8c4931522922cd706105aa32b3291d1add8c5427cdcd66e63/kiwisolver-1.4.8-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a5ce1e481a74b44dd5e92ff03ea0cb371ae7a0268318e202be06c8f04f4f1246", size = 1474952, upload-time = "2024-12-24T18:29:56.523Z" }, + { url = "https://files.pythonhosted.org/packages/82/13/13fa685ae167bee5d94b415991c4fc7bb0a1b6ebea6e753a87044b209678/kiwisolver-1.4.8-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:fc2ace710ba7c1dfd1a3b42530b62b9ceed115f19a1656adefce7b1782a37794", size = 2269132, upload-time = "2024-12-24T18:29:57.989Z" }, + { url = "https://files.pythonhosted.org/packages/ef/92/bb7c9395489b99a6cb41d502d3686bac692586db2045adc19e45ee64ed23/kiwisolver-1.4.8-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:3452046c37c7692bd52b0e752b87954ef86ee2224e624ef7ce6cb21e8c41cc1b", size = 2425997, upload-time = "2024-12-24T18:29:59.393Z" }, + { url = "https://files.pythonhosted.org/packages/ed/12/87f0e9271e2b63d35d0d8524954145837dd1a6c15b62a2d8c1ebe0f182b4/kiwisolver-1.4.8-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:7e9a60b50fe8b2ec6f448fe8d81b07e40141bfced7f896309df271a0b92f80f3", size = 2376060, upload-time = "2024-12-24T18:30:01.338Z" }, + { url = "https://files.pythonhosted.org/packages/02/6e/c8af39288edbce8bf0fa35dee427b082758a4b71e9c91ef18fa667782138/kiwisolver-1.4.8-cp313-cp313-musllinux_1_2_s390x.whl", hash = "sha256:918139571133f366e8362fa4a297aeba86c7816b7ecf0bc79168080e2bd79957", size = 2520471, upload-time = "2024-12-24T18:30:04.574Z" }, + { url = "https://files.pythonhosted.org/packages/13/78/df381bc7b26e535c91469f77f16adcd073beb3e2dd25042efd064af82323/kiwisolver-1.4.8-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:e063ef9f89885a1d68dd8b2e18f5ead48653176d10a0e324e3b0030e3a69adeb", size = 2338793, upload-time = "2024-12-24T18:30:06.25Z" }, + { url = "https://files.pythonhosted.org/packages/d0/dc/c1abe38c37c071d0fc71c9a474fd0b9ede05d42f5a458d584619cfd2371a/kiwisolver-1.4.8-cp313-cp313-win_amd64.whl", hash = "sha256:a17b7c4f5b2c51bb68ed379defd608a03954a1845dfed7cc0117f1cc8a9b7fd2", size = 71855, upload-time = "2024-12-24T18:30:07.535Z" }, + { url = "https://files.pythonhosted.org/packages/a0/b6/21529d595b126ac298fdd90b705d87d4c5693de60023e0efcb4f387ed99e/kiwisolver-1.4.8-cp313-cp313-win_arm64.whl", hash = "sha256:3cd3bc628b25f74aedc6d374d5babf0166a92ff1317f46267f12d2ed54bc1d30", size = 65430, upload-time = "2024-12-24T18:30:08.504Z" }, + { url = "https://files.pythonhosted.org/packages/34/bd/b89380b7298e3af9b39f49334e3e2a4af0e04819789f04b43d560516c0c8/kiwisolver-1.4.8-cp313-cp313t-macosx_10_13_universal2.whl", hash = "sha256:370fd2df41660ed4e26b8c9d6bbcad668fbe2560462cba151a721d49e5b6628c", size = 126294, upload-time = "2024-12-24T18:30:09.508Z" }, + { url = "https://files.pythonhosted.org/packages/83/41/5857dc72e5e4148eaac5aa76e0703e594e4465f8ab7ec0fc60e3a9bb8fea/kiwisolver-1.4.8-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:84a2f830d42707de1d191b9490ac186bf7997a9495d4e9072210a1296345f7dc", size = 67736, upload-time = "2024-12-24T18:30:11.039Z" }, + { url = "https://files.pythonhosted.org/packages/e1/d1/be059b8db56ac270489fb0b3297fd1e53d195ba76e9bbb30e5401fa6b759/kiwisolver-1.4.8-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:7a3ad337add5148cf51ce0b55642dc551c0b9d6248458a757f98796ca7348712", size = 66194, upload-time = "2024-12-24T18:30:14.886Z" }, + { url = "https://files.pythonhosted.org/packages/e1/83/4b73975f149819eb7dcf9299ed467eba068ecb16439a98990dcb12e63fdd/kiwisolver-1.4.8-cp313-cp313t-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:7506488470f41169b86d8c9aeff587293f530a23a23a49d6bc64dab66bedc71e", size = 1465942, upload-time = "2024-12-24T18:30:18.927Z" }, + { url = "https://files.pythonhosted.org/packages/c7/2c/30a5cdde5102958e602c07466bce058b9d7cb48734aa7a4327261ac8e002/kiwisolver-1.4.8-cp313-cp313t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:2f0121b07b356a22fb0414cec4666bbe36fd6d0d759db3d37228f496ed67c880", size = 1595341, upload-time = "2024-12-24T18:30:22.102Z" }, + { url = "https://files.pythonhosted.org/packages/ff/9b/1e71db1c000385aa069704f5990574b8244cce854ecd83119c19e83c9586/kiwisolver-1.4.8-cp313-cp313t-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:d6d6bd87df62c27d4185de7c511c6248040afae67028a8a22012b010bc7ad062", size = 1598455, upload-time = "2024-12-24T18:30:24.947Z" }, + { url = "https://files.pythonhosted.org/packages/85/92/c8fec52ddf06231b31cbb779af77e99b8253cd96bd135250b9498144c78b/kiwisolver-1.4.8-cp313-cp313t-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:291331973c64bb9cce50bbe871fb2e675c4331dab4f31abe89f175ad7679a4d7", size = 1522138, upload-time = "2024-12-24T18:30:26.286Z" }, + { url = "https://files.pythonhosted.org/packages/0b/51/9eb7e2cd07a15d8bdd976f6190c0164f92ce1904e5c0c79198c4972926b7/kiwisolver-1.4.8-cp313-cp313t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:893f5525bb92d3d735878ec00f781b2de998333659507d29ea4466208df37bed", size = 1582857, upload-time = "2024-12-24T18:30:28.86Z" }, + { url = "https://files.pythonhosted.org/packages/0f/95/c5a00387a5405e68ba32cc64af65ce881a39b98d73cc394b24143bebc5b8/kiwisolver-1.4.8-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:b47a465040146981dc9db8647981b8cb96366fbc8d452b031e4f8fdffec3f26d", size = 2293129, upload-time = "2024-12-24T18:30:30.34Z" }, + { url = "https://files.pythonhosted.org/packages/44/83/eeb7af7d706b8347548313fa3a3a15931f404533cc54fe01f39e830dd231/kiwisolver-1.4.8-cp313-cp313t-musllinux_1_2_i686.whl", hash = "sha256:99cea8b9dd34ff80c521aef46a1dddb0dcc0283cf18bde6d756f1e6f31772165", size = 2421538, upload-time = "2024-12-24T18:30:33.334Z" }, + { 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]] +name = "loguru" +version = "0.7.3" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "colorama", marker = "sys_platform == 'win32'" }, + { name = "win32-setctime", marker = "sys_platform == 'win32'" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/3a/05/a1dae3dffd1116099471c643b8924f5aa6524411dc6c63fdae648c4f1aca/loguru-0.7.3.tar.gz", hash = "sha256:19480589e77d47b8d85b2c827ad95d49bf31b0dcde16593892eb51dd18706eb6", size = 63559, upload-time = "2024-12-06T11:20:56.608Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/0c/29/0348de65b8cc732daa3e33e67806420b2ae89bdce2b04af740289c5c6c8c/loguru-0.7.3-py3-none-any.whl", hash = "sha256:31a33c10c8e1e10422bfd431aeb5d351c7cf7fa671e3c4df004162264b28220c", size = 61595, upload-time = "2024-12-06T11:20:54.538Z" }, +] + +[[package]] +name = "matplotlib" +version = "3.10.3" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "contourpy" }, + { name = "cycler" }, + { name = "fonttools" }, + { name = "kiwisolver" }, + { name = "numpy", version = "2.2.6", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version < '3.11'" }, + { name = "numpy", version = "2.3.0", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.11'" }, + { name = "packaging" }, + { name = "pillow" }, + { name = "pyparsing" }, + { name = "python-dateutil" }, +] +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" }, + { url = "https://files.pythonhosted.org/packages/e7/e3/c82963a3b86d6e6d5874cbeaa390166458a7f1961bab9feb14d3d1a10f02/matplotlib-3.10.3-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:fdfa07c0ec58035242bc8b2c8aae37037c9a886370eef6850703d7583e19964b", size = 8606464, upload-time = "2025-05-08T19:09:59.471Z" }, + { url = "https://files.pythonhosted.org/packages/0e/34/24da1027e7fcdd9e82da3194c470143c551852757a4b473a09a012f5b945/matplotlib-3.10.3-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:c0b9849a17bce080a16ebcb80a7b714b5677d0ec32161a2cc0a8e5a6030ae220", size = 9413103, upload-time = "2025-05-08T19:10:03.208Z" }, + { url = "https://files.pythonhosted.org/packages/a6/da/948a017c3ea13fd4a97afad5fdebe2f5bbc4d28c0654510ce6fd6b06b7bd/matplotlib-3.10.3-cp311-cp311-win_amd64.whl", hash = "sha256:eef6ed6c03717083bc6d69c2d7ee8624205c29a8e6ea5a31cd3492ecdbaee1e1", size = 8065492, upload-time = "2025-05-08T19:10:05.271Z" }, + { url = "https://files.pythonhosted.org/packages/eb/43/6b80eb47d1071f234ef0c96ca370c2ca621f91c12045f1401b5c9b28a639/matplotlib-3.10.3-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:0ab1affc11d1f495ab9e6362b8174a25afc19c081ba5b0775ef00533a4236eea", size = 8179689, upload-time = "2025-05-08T19:10:07.602Z" }, + { url = "https://files.pythonhosted.org/packages/0f/70/d61a591958325c357204870b5e7b164f93f2a8cca1dc6ce940f563909a13/matplotlib-3.10.3-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:2a818d8bdcafa7ed2eed74487fdb071c09c1ae24152d403952adad11fa3c65b4", size = 8050466, upload-time = "2025-05-08T19:10:09.383Z" }, + { url = "https://files.pythonhosted.org/packages/e7/75/70c9d2306203148cc7902a961240c5927dd8728afedf35e6a77e105a2985/matplotlib-3.10.3-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:748ebc3470c253e770b17d8b0557f0aa85cf8c63fd52f1a61af5b27ec0b7ffee", size = 8456252, upload-time = "2025-05-08T19:10:11.958Z" }, + { url = "https://files.pythonhosted.org/packages/c4/91/ba0ae1ff4b3f30972ad01cd4a8029e70a0ec3b8ea5be04764b128b66f763/matplotlib-3.10.3-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ed70453fd99733293ace1aec568255bc51c6361cb0da94fa5ebf0649fdb2150a", size = 8601321, upload-time = "2025-05-08T19:10:14.47Z" }, + { url = "https://files.pythonhosted.org/packages/d2/88/d636041eb54a84b889e11872d91f7cbf036b3b0e194a70fa064eb8b04f7a/matplotlib-3.10.3-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:dbed9917b44070e55640bd13419de83b4c918e52d97561544814ba463811cbc7", size = 9406972, upload-time = "2025-05-08T19:10:16.569Z" }, + { url = "https://files.pythonhosted.org/packages/b1/79/0d1c165eac44405a86478082e225fce87874f7198300bbebc55faaf6d28d/matplotlib-3.10.3-cp312-cp312-win_amd64.whl", hash = "sha256:cf37d8c6ef1a48829443e8ba5227b44236d7fcaf7647caa3178a4ff9f7a5be05", size = 8067954, upload-time = "2025-05-08T19:10:18.663Z" }, + { url = "https://files.pythonhosted.org/packages/3b/c1/23cfb566a74c696a3b338d8955c549900d18fe2b898b6e94d682ca21e7c2/matplotlib-3.10.3-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:9f2efccc8dcf2b86fc4ee849eea5dcaecedd0773b30f47980dc0cbeabf26ec84", size = 8180318, upload-time = "2025-05-08T19:10:20.426Z" }, + { url = "https://files.pythonhosted.org/packages/6c/0c/02f1c3b66b30da9ee343c343acbb6251bef5b01d34fad732446eaadcd108/matplotlib-3.10.3-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:3ddbba06a6c126e3301c3d272a99dcbe7f6c24c14024e80307ff03791a5f294e", size = 8051132, upload-time = "2025-05-08T19:10:22.569Z" }, + { url = "https://files.pythonhosted.org/packages/b4/ab/8db1a5ac9b3a7352fb914133001dae889f9fcecb3146541be46bed41339c/matplotlib-3.10.3-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:748302b33ae9326995b238f606e9ed840bf5886ebafcb233775d946aa8107a15", size = 8457633, upload-time = "2025-05-08T19:10:24.749Z" }, + { url = "https://files.pythonhosted.org/packages/f5/64/41c4367bcaecbc03ef0d2a3ecee58a7065d0a36ae1aa817fe573a2da66d4/matplotlib-3.10.3-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a80fcccbef63302c0efd78042ea3c2436104c5b1a4d3ae20f864593696364ac7", size = 8601031, upload-time = "2025-05-08T19:10:27.03Z" }, + { url = "https://files.pythonhosted.org/packages/12/6f/6cc79e9e5ab89d13ed64da28898e40fe5b105a9ab9c98f83abd24e46d7d7/matplotlib-3.10.3-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:55e46cbfe1f8586adb34f7587c3e4f7dedc59d5226719faf6cb54fc24f2fd52d", size = 9406988, upload-time = "2025-05-08T19:10:29.056Z" }, + { url = "https://files.pythonhosted.org/packages/b1/0f/eed564407bd4d935ffabf561ed31099ed609e19287409a27b6d336848653/matplotlib-3.10.3-cp313-cp313-win_amd64.whl", hash = "sha256:151d89cb8d33cb23345cd12490c76fd5d18a56581a16d950b48c6ff19bb2ab93", size = 8068034, upload-time = "2025-05-08T19:10:31.221Z" }, + { url = "https://files.pythonhosted.org/packages/3e/e5/2f14791ff69b12b09e9975e1d116d9578ac684460860ce542c2588cb7a1c/matplotlib-3.10.3-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:c26dd9834e74d164d06433dc7be5d75a1e9890b926b3e57e74fa446e1a62c3e2", size = 8218223, upload-time = "2025-05-08T19:10:33.114Z" }, + { url = "https://files.pythonhosted.org/packages/5c/08/30a94afd828b6e02d0a52cae4a29d6e9ccfcf4c8b56cc28b021d3588873e/matplotlib-3.10.3-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:24853dad5b8c84c8c2390fc31ce4858b6df504156893292ce8092d190ef8151d", size = 8094985, upload-time = "2025-05-08T19:10:35.337Z" }, + { url = "https://files.pythonhosted.org/packages/89/44/f3bc6b53066c889d7a1a3ea8094c13af6a667c5ca6220ec60ecceec2dabe/matplotlib-3.10.3-cp313-cp313t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:68f7878214d369d7d4215e2a9075fef743be38fa401d32e6020bab2dfabaa566", size = 8483109, upload-time = "2025-05-08T19:10:37.611Z" }, + { 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]] +name = "more-itertools" +version = "10.7.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/ce/a0/834b0cebabbfc7e311f30b46c8188790a37f89fc8d756660346fe5abfd09/more_itertools-10.7.0.tar.gz", hash = "sha256:9fddd5403be01a94b204faadcff459ec3568cf110265d3c54323e1e866ad29d3", size = 127671, upload-time = "2025-04-22T14:17:41.838Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/2b/9f/7ba6f94fc1e9ac3d2b853fdff3035fb2fa5afbed898c4a72b8a020610594/more_itertools-10.7.0-py3-none-any.whl", hash = "sha256:d43980384673cb07d2f7d2d918c616b30c659c089ee23953f601d6609c67510e", size = 65278, upload-time = "2025-04-22T14:17:40.49Z" }, +] + +[[package]] +name = "nodeenv" +version = "1.9.1" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/43/16/fc88b08840de0e0a72a2f9d8c6bae36be573e475a6326ae854bcc549fc45/nodeenv-1.9.1.tar.gz", hash = "sha256:6ec12890a2dab7946721edbfbcd91f3319c6ccc9aec47be7c7e6b7011ee6645f", size = 47437, upload-time = "2024-06-04T18:44:11.171Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/d2/1d/1b658dbd2b9fa9c4c9f32accbfc0205d532c8c6194dc0f2a4c0428e7128a/nodeenv-1.9.1-py2.py3-none-any.whl", hash = "sha256:ba11c9782d29c27c70ffbdda2d7415098754709be8a7056d79a737cd901155c9", size = 22314, upload-time = "2024-06-04T18:44:08.352Z" }, +] + +[[package]] +name = "numpy" +version = "2.2.6" +source = { registry = "https://pypi.org/simple" } +resolution-markers = [ + "python_full_version < '3.11'", +] +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" }, + { url = "https://files.pythonhosted.org/packages/31/0d/b48c405c91693635fbe2dcd7bc84a33a602add5f63286e024d3b6741411c/numpy-2.2.6-cp311-cp311-macosx_14_0_x86_64.whl", hash = "sha256:481b49095335f8eed42e39e8041327c05b0f6f4780488f61286ed3c01368d491", size = 6889579, upload-time = "2025-05-17T21:32:01.712Z" }, + { url = "https://files.pythonhosted.org/packages/52/b8/7f0554d49b565d0171eab6e99001846882000883998e7b7d9f0d98b1f934/numpy-2.2.6-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b64d8d4d17135e00c8e346e0a738deb17e754230d7e0810ac5012750bbd85a5a", size = 14312005, upload-time = "2025-05-17T21:32:23.332Z" }, + { url = "https://files.pythonhosted.org/packages/b3/dd/2238b898e51bd6d389b7389ffb20d7f4c10066d80351187ec8e303a5a475/numpy-2.2.6-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ba10f8411898fc418a521833e014a77d3ca01c15b0c6cdcce6a0d2897e6dbbdf", size = 16821570, upload-time = "2025-05-17T21:32:47.991Z" }, + { url = "https://files.pythonhosted.org/packages/83/6c/44d0325722cf644f191042bf47eedad61c1e6df2432ed65cbe28509d404e/numpy-2.2.6-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:bd48227a919f1bafbdda0583705e547892342c26fb127219d60a5c36882609d1", size = 15818548, upload-time = "2025-05-17T21:33:11.728Z" }, + { url = "https://files.pythonhosted.org/packages/ae/9d/81e8216030ce66be25279098789b665d49ff19eef08bfa8cb96d4957f422/numpy-2.2.6-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:9551a499bf125c1d4f9e250377c1ee2eddd02e01eac6644c080162c0c51778ab", size = 18620521, upload-time = "2025-05-17T21:33:39.139Z" }, + { url = "https://files.pythonhosted.org/packages/6a/fd/e19617b9530b031db51b0926eed5345ce8ddc669bb3bc0044b23e275ebe8/numpy-2.2.6-cp311-cp311-win32.whl", hash = "sha256:0678000bb9ac1475cd454c6b8c799206af8107e310843532b04d49649c717a47", size = 6525866, upload-time = "2025-05-17T21:33:50.273Z" }, + { url = "https://files.pythonhosted.org/packages/31/0a/f354fb7176b81747d870f7991dc763e157a934c717b67b58456bc63da3df/numpy-2.2.6-cp311-cp311-win_amd64.whl", hash = "sha256:e8213002e427c69c45a52bbd94163084025f533a55a59d6f9c5b820774ef3303", size = 12907455, upload-time = "2025-05-17T21:34:09.135Z" }, + { url = "https://files.pythonhosted.org/packages/82/5d/c00588b6cf18e1da539b45d3598d3557084990dcc4331960c15ee776ee41/numpy-2.2.6-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:41c5a21f4a04fa86436124d388f6ed60a9343a6f767fced1a8a71c3fbca038ff", size = 20875348, upload-time = "2025-05-17T21:34:39.648Z" }, + { url = "https://files.pythonhosted.org/packages/66/ee/560deadcdde6c2f90200450d5938f63a34b37e27ebff162810f716f6a230/numpy-2.2.6-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:de749064336d37e340f640b05f24e9e3dd678c57318c7289d222a8a2f543e90c", size = 14119362, upload-time = "2025-05-17T21:35:01.241Z" }, + { url = "https://files.pythonhosted.org/packages/3c/65/4baa99f1c53b30adf0acd9a5519078871ddde8d2339dc5a7fde80d9d87da/numpy-2.2.6-cp312-cp312-macosx_14_0_arm64.whl", hash = "sha256:894b3a42502226a1cac872f840030665f33326fc3dac8e57c607905773cdcde3", size = 5084103, upload-time = "2025-05-17T21:35:10.622Z" }, + { url = "https://files.pythonhosted.org/packages/cc/89/e5a34c071a0570cc40c9a54eb472d113eea6d002e9ae12bb3a8407fb912e/numpy-2.2.6-cp312-cp312-macosx_14_0_x86_64.whl", hash = "sha256:71594f7c51a18e728451bb50cc60a3ce4e6538822731b2933209a1f3614e9282", size = 6625382, upload-time = "2025-05-17T21:35:21.414Z" }, + { url = "https://files.pythonhosted.org/packages/f8/35/8c80729f1ff76b3921d5c9487c7ac3de9b2a103b1cd05e905b3090513510/numpy-2.2.6-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f2618db89be1b4e05f7a1a847a9c1c0abd63e63a1607d892dd54668dd92faf87", size = 14018462, upload-time = "2025-05-17T21:35:42.174Z" }, + { url = "https://files.pythonhosted.org/packages/8c/3d/1e1db36cfd41f895d266b103df00ca5b3cbe965184df824dec5c08c6b803/numpy-2.2.6-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:fd83c01228a688733f1ded5201c678f0c53ecc1006ffbc404db9f7a899ac6249", size = 16527618, upload-time = "2025-05-17T21:36:06.711Z" }, + { url = "https://files.pythonhosted.org/packages/61/c6/03ed30992602c85aa3cd95b9070a514f8b3c33e31124694438d88809ae36/numpy-2.2.6-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:37c0ca431f82cd5fa716eca9506aefcabc247fb27ba69c5062a6d3ade8cf8f49", size = 15505511, upload-time = "2025-05-17T21:36:29.965Z" }, + { url = "https://files.pythonhosted.org/packages/b7/25/5761d832a81df431e260719ec45de696414266613c9ee268394dd5ad8236/numpy-2.2.6-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:fe27749d33bb772c80dcd84ae7e8df2adc920ae8297400dabec45f0dedb3f6de", size = 18313783, upload-time = "2025-05-17T21:36:56.883Z" }, + { url = "https://files.pythonhosted.org/packages/57/0a/72d5a3527c5ebffcd47bde9162c39fae1f90138c961e5296491ce778e682/numpy-2.2.6-cp312-cp312-win32.whl", hash = "sha256:4eeaae00d789f66c7a25ac5f34b71a7035bb474e679f410e5e1a94deb24cf2d4", size = 6246506, upload-time = "2025-05-17T21:37:07.368Z" }, + { url = "https://files.pythonhosted.org/packages/36/fa/8c9210162ca1b88529ab76b41ba02d433fd54fecaf6feb70ef9f124683f1/numpy-2.2.6-cp312-cp312-win_amd64.whl", hash = "sha256:c1f9540be57940698ed329904db803cf7a402f3fc200bfe599334c9bd84a40b2", size = 12614190, upload-time = "2025-05-17T21:37:26.213Z" }, + { url = "https://files.pythonhosted.org/packages/f9/5c/6657823f4f594f72b5471f1db1ab12e26e890bb2e41897522d134d2a3e81/numpy-2.2.6-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:0811bb762109d9708cca4d0b13c4f67146e3c3b7cf8d34018c722adb2d957c84", size = 20867828, upload-time = "2025-05-17T21:37:56.699Z" }, + { url = "https://files.pythonhosted.org/packages/dc/9e/14520dc3dadf3c803473bd07e9b2bd1b69bc583cb2497b47000fed2fa92f/numpy-2.2.6-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:287cc3162b6f01463ccd86be154f284d0893d2b3ed7292439ea97eafa8170e0b", size = 14143006, upload-time = "2025-05-17T21:38:18.291Z" }, + { url = "https://files.pythonhosted.org/packages/4f/06/7e96c57d90bebdce9918412087fc22ca9851cceaf5567a45c1f404480e9e/numpy-2.2.6-cp313-cp313-macosx_14_0_arm64.whl", hash = "sha256:f1372f041402e37e5e633e586f62aa53de2eac8d98cbfb822806ce4bbefcb74d", size = 5076765, upload-time = "2025-05-17T21:38:27.319Z" }, + { url = "https://files.pythonhosted.org/packages/73/ed/63d920c23b4289fdac96ddbdd6132e9427790977d5457cd132f18e76eae0/numpy-2.2.6-cp313-cp313-macosx_14_0_x86_64.whl", hash = "sha256:55a4d33fa519660d69614a9fad433be87e5252f4b03850642f88993f7b2ca566", size = 6617736, upload-time = "2025-05-17T21:38:38.141Z" }, + { url = "https://files.pythonhosted.org/packages/85/c5/e19c8f99d83fd377ec8c7e0cf627a8049746da54afc24ef0a0cb73d5dfb5/numpy-2.2.6-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f92729c95468a2f4f15e9bb94c432a9229d0d50de67304399627a943201baa2f", size = 14010719, upload-time = "2025-05-17T21:38:58.433Z" }, + { url = "https://files.pythonhosted.org/packages/19/49/4df9123aafa7b539317bf6d342cb6d227e49f7a35b99c287a6109b13dd93/numpy-2.2.6-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:1bc23a79bfabc5d056d106f9befb8d50c31ced2fbc70eedb8155aec74a45798f", size = 16526072, upload-time = "2025-05-17T21:39:22.638Z" }, + { url = "https://files.pythonhosted.org/packages/b2/6c/04b5f47f4f32f7c2b0e7260442a8cbcf8168b0e1a41ff1495da42f42a14f/numpy-2.2.6-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:e3143e4451880bed956e706a3220b4e5cf6172ef05fcc397f6f36a550b1dd868", size = 15503213, upload-time = "2025-05-17T21:39:45.865Z" }, + { url = "https://files.pythonhosted.org/packages/17/0a/5cd92e352c1307640d5b6fec1b2ffb06cd0dabe7d7b8227f97933d378422/numpy-2.2.6-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:b4f13750ce79751586ae2eb824ba7e1e8dba64784086c98cdbbcc6a42112ce0d", size = 18316632, upload-time = "2025-05-17T21:40:13.331Z" }, + { url = "https://files.pythonhosted.org/packages/f0/3b/5cba2b1d88760ef86596ad0f3d484b1cbff7c115ae2429678465057c5155/numpy-2.2.6-cp313-cp313-win32.whl", hash = "sha256:5beb72339d9d4fa36522fc63802f469b13cdbe4fdab4a288f0c441b74272ebfd", size = 6244532, upload-time = "2025-05-17T21:43:46.099Z" }, + { url = "https://files.pythonhosted.org/packages/cb/3b/d58c12eafcb298d4e6d0d40216866ab15f59e55d148a5658bb3132311fcf/numpy-2.2.6-cp313-cp313-win_amd64.whl", hash = "sha256:b0544343a702fa80c95ad5d3d608ea3599dd54d4632df855e4c8d24eb6ecfa1c", size = 12610885, upload-time = "2025-05-17T21:44:05.145Z" }, + { url = "https://files.pythonhosted.org/packages/6b/9e/4bf918b818e516322db999ac25d00c75788ddfd2d2ade4fa66f1f38097e1/numpy-2.2.6-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:0bca768cd85ae743b2affdc762d617eddf3bcf8724435498a1e80132d04879e6", size = 20963467, upload-time = "2025-05-17T21:40:44Z" }, + { url = "https://files.pythonhosted.org/packages/61/66/d2de6b291507517ff2e438e13ff7b1e2cdbdb7cb40b3ed475377aece69f9/numpy-2.2.6-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:fc0c5673685c508a142ca65209b4e79ed6740a4ed6b2267dbba90f34b0b3cfda", size = 14225144, upload-time = "2025-05-17T21:41:05.695Z" }, + { url = "https://files.pythonhosted.org/packages/e4/25/480387655407ead912e28ba3a820bc69af9adf13bcbe40b299d454ec011f/numpy-2.2.6-cp313-cp313t-macosx_14_0_arm64.whl", hash = "sha256:5bd4fc3ac8926b3819797a7c0e2631eb889b4118a9898c84f585a54d475b7e40", size = 5200217, upload-time = "2025-05-17T21:41:15.903Z" }, + { url = "https://files.pythonhosted.org/packages/aa/4a/6e313b5108f53dcbf3aca0c0f3e9c92f4c10ce57a0a721851f9785872895/numpy-2.2.6-cp313-cp313t-macosx_14_0_x86_64.whl", hash = "sha256:fee4236c876c4e8369388054d02d0e9bb84821feb1a64dd59e137e6511a551f8", size = 6712014, upload-time = "2025-05-17T21:41:27.321Z" }, + { url = "https://files.pythonhosted.org/packages/b7/30/172c2d5c4be71fdf476e9de553443cf8e25feddbe185e0bd88b096915bcc/numpy-2.2.6-cp313-cp313t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e1dda9c7e08dc141e0247a5b8f49cf05984955246a327d4c48bda16821947b2f", size = 14077935, upload-time = "2025-05-17T21:41:49.738Z" }, + { url = "https://files.pythonhosted.org/packages/12/fb/9e743f8d4e4d3c710902cf87af3512082ae3d43b945d5d16563f26ec251d/numpy-2.2.6-cp313-cp313t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f447e6acb680fd307f40d3da4852208af94afdfab89cf850986c3ca00562f4fa", size = 16600122, upload-time = "2025-05-17T21:42:14.046Z" }, + { url = "https://files.pythonhosted.org/packages/12/75/ee20da0e58d3a66f204f38916757e01e33a9737d0b22373b3eb5a27358f9/numpy-2.2.6-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:389d771b1623ec92636b0786bc4ae56abafad4a4c513d36a55dce14bd9ce8571", size = 15586143, upload-time = "2025-05-17T21:42:37.464Z" }, + { 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]] +name = "numpy" +version = "2.3.0" +source = { registry = "https://pypi.org/simple" } +resolution-markers = [ + "python_full_version >= '3.11'", +] +sdist = { url = "https://files.pythonhosted.org/packages/f3/db/8e12381333aea300890829a0a36bfa738cac95475d88982d538725143fd9/numpy-2.3.0.tar.gz", hash = "sha256:581f87f9e9e9db2cba2141400e160e9dd644ee248788d6f90636eeb8fd9260a6", size = 20382813, upload-time = "2025-06-07T14:54:32.608Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/fd/5f/df67435257d827eb3b8af66f585223dc2c3f2eb7ad0b50cb1dae2f35f494/numpy-2.3.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:c3c9fdde0fa18afa1099d6257eb82890ea4f3102847e692193b54e00312a9ae9", size = 21199688, upload-time = "2025-06-07T14:36:52.067Z" }, + { url = "https://files.pythonhosted.org/packages/e5/ce/aad219575055d6c9ef29c8c540c81e1c38815d3be1fe09cdbe53d48ee838/numpy-2.3.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:46d16f72c2192da7b83984aa5455baee640e33a9f1e61e656f29adf55e406c2b", size = 14359277, upload-time = "2025-06-07T14:37:15.325Z" }, + { url = "https://files.pythonhosted.org/packages/29/6b/2d31da8e6d2ec99bed54c185337a87f8fbeccc1cd9804e38217e92f3f5e2/numpy-2.3.0-cp311-cp311-macosx_14_0_arm64.whl", hash = "sha256:a0be278be9307c4ab06b788f2a077f05e180aea817b3e41cebbd5aaf7bd85ed3", size = 5376069, upload-time = "2025-06-07T14:37:25.636Z" }, + { url = "https://files.pythonhosted.org/packages/7d/2a/6c59a062397553ec7045c53d5fcdad44e4536e54972faa2ba44153bca984/numpy-2.3.0-cp311-cp311-macosx_14_0_x86_64.whl", hash = "sha256:99224862d1412d2562248d4710126355d3a8db7672170a39d6909ac47687a8a4", size = 6913057, upload-time = "2025-06-07T14:37:37.215Z" }, + { url = "https://files.pythonhosted.org/packages/d5/5a/8df16f258d28d033e4f359e29d3aeb54663243ac7b71504e89deeb813202/numpy-2.3.0-cp311-cp311-manylinux_2_28_aarch64.whl", hash = "sha256:2393a914db64b0ead0ab80c962e42d09d5f385802006a6c87835acb1f58adb96", size = 14568083, upload-time = "2025-06-07T14:37:59.337Z" }, + { url = "https://files.pythonhosted.org/packages/0a/92/0528a563dfc2cdccdcb208c0e241a4bb500d7cde218651ffb834e8febc50/numpy-2.3.0-cp311-cp311-manylinux_2_28_x86_64.whl", hash = "sha256:7729c8008d55e80784bd113787ce876ca117185c579c0d626f59b87d433ea779", size = 16929402, upload-time = "2025-06-07T14:38:24.343Z" }, + { url = "https://files.pythonhosted.org/packages/e4/2f/e7a8c8d4a2212c527568d84f31587012cf5497a7271ea1f23332142f634e/numpy-2.3.0-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:06d4fb37a8d383b769281714897420c5cc3545c79dc427df57fc9b852ee0bf58", size = 15879193, upload-time = "2025-06-07T14:38:48.007Z" }, + { url = "https://files.pythonhosted.org/packages/e2/c3/dada3f005953847fe35f42ac0fe746f6e1ea90b4c6775e4be605dcd7b578/numpy-2.3.0-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:c39ec392b5db5088259c68250e342612db82dc80ce044cf16496cf14cf6bc6f8", size = 18665318, upload-time = "2025-06-07T14:39:15.794Z" }, + { url = "https://files.pythonhosted.org/packages/3b/ae/3f448517dedefc8dd64d803f9d51a8904a48df730e00a3c5fb1e75a60620/numpy-2.3.0-cp311-cp311-win32.whl", hash = "sha256:ee9d3ee70d62827bc91f3ea5eee33153212c41f639918550ac0475e3588da59f", size = 6601108, upload-time = "2025-06-07T14:39:27.176Z" }, + { url = "https://files.pythonhosted.org/packages/8c/4a/556406d2bb2b9874c8cbc840c962683ac28f21efbc9b01177d78f0199ca1/numpy-2.3.0-cp311-cp311-win_amd64.whl", hash = "sha256:43c55b6a860b0eb44d42341438b03513cf3879cb3617afb749ad49307e164edd", size = 13021525, upload-time = "2025-06-07T14:39:46.637Z" }, + { url = "https://files.pythonhosted.org/packages/ed/ee/bf54278aef30335ffa9a189f869ea09e1a195b3f4b93062164a3b02678a7/numpy-2.3.0-cp311-cp311-win_arm64.whl", hash = "sha256:2e6a1409eee0cb0316cb64640a49a49ca44deb1a537e6b1121dc7c458a1299a8", size = 10170327, upload-time = "2025-06-07T14:40:02.703Z" }, + { url = "https://files.pythonhosted.org/packages/89/59/9df493df81ac6f76e9f05cdbe013cdb0c9a37b434f6e594f5bd25e278908/numpy-2.3.0-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:389b85335838155a9076e9ad7f8fdba0827496ec2d2dc32ce69ce7898bde03ba", size = 20897025, upload-time = "2025-06-07T14:40:33.558Z" }, + { url = "https://files.pythonhosted.org/packages/2f/86/4ff04335901d6cf3a6bb9c748b0097546ae5af35e455ae9b962ebff4ecd7/numpy-2.3.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:9498f60cd6bb8238d8eaf468a3d5bb031d34cd12556af53510f05fcf581c1b7e", size = 14129882, upload-time = "2025-06-07T14:40:55.034Z" }, + { url = "https://files.pythonhosted.org/packages/71/8d/a942cd4f959de7f08a79ab0c7e6cecb7431d5403dce78959a726f0f57aa1/numpy-2.3.0-cp312-cp312-macosx_14_0_arm64.whl", hash = "sha256:622a65d40d8eb427d8e722fd410ac3ad4958002f109230bc714fa551044ebae2", size = 5110181, upload-time = "2025-06-07T14:41:04.4Z" }, + { url = "https://files.pythonhosted.org/packages/86/5d/45850982efc7b2c839c5626fb67fbbc520d5b0d7c1ba1ae3651f2f74c296/numpy-2.3.0-cp312-cp312-macosx_14_0_x86_64.whl", hash = "sha256:b9446d9d8505aadadb686d51d838f2b6688c9e85636a0c3abaeb55ed54756459", size = 6647581, upload-time = "2025-06-07T14:41:14.695Z" }, + { url = "https://files.pythonhosted.org/packages/1a/c0/c871d4a83f93b00373d3eebe4b01525eee8ef10b623a335ec262b58f4dc1/numpy-2.3.0-cp312-cp312-manylinux_2_28_aarch64.whl", hash = "sha256:50080245365d75137a2bf46151e975de63146ae6d79f7e6bd5c0e85c9931d06a", size = 14262317, upload-time = "2025-06-07T14:41:35.862Z" }, + { url = "https://files.pythonhosted.org/packages/b7/f6/bc47f5fa666d5ff4145254f9e618d56e6a4ef9b874654ca74c19113bb538/numpy-2.3.0-cp312-cp312-manylinux_2_28_x86_64.whl", hash = "sha256:c24bb4113c66936eeaa0dc1e47c74770453d34f46ee07ae4efd853a2ed1ad10a", size = 16633919, upload-time = "2025-06-07T14:42:00.622Z" }, + { url = "https://files.pythonhosted.org/packages/f5/b4/65f48009ca0c9b76df5f404fccdea5a985a1bb2e34e97f21a17d9ad1a4ba/numpy-2.3.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:4d8d294287fdf685281e671886c6dcdf0291a7c19db3e5cb4178d07ccf6ecc67", size = 15567651, upload-time = "2025-06-07T14:42:24.429Z" }, + { url = "https://files.pythonhosted.org/packages/f1/62/5367855a2018578e9334ed08252ef67cc302e53edc869666f71641cad40b/numpy-2.3.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:6295f81f093b7f5769d1728a6bd8bf7466de2adfa771ede944ce6711382b89dc", size = 18361723, upload-time = "2025-06-07T14:42:51.167Z" }, + { url = "https://files.pythonhosted.org/packages/d4/75/5baed8cd867eabee8aad1e74d7197d73971d6a3d40c821f1848b8fab8b84/numpy-2.3.0-cp312-cp312-win32.whl", hash = "sha256:e6648078bdd974ef5d15cecc31b0c410e2e24178a6e10bf511e0557eed0f2570", size = 6318285, upload-time = "2025-06-07T14:43:02.052Z" }, + { url = "https://files.pythonhosted.org/packages/bc/49/d5781eaa1a15acb3b3a3f49dc9e2ff18d92d0ce5c2976f4ab5c0a7360250/numpy-2.3.0-cp312-cp312-win_amd64.whl", hash = "sha256:0898c67a58cdaaf29994bc0e2c65230fd4de0ac40afaf1584ed0b02cd74c6fdd", size = 12732594, upload-time = "2025-06-07T14:43:21.071Z" }, + { url = "https://files.pythonhosted.org/packages/c2/1c/6d343e030815c7c97a1f9fbad00211b47717c7fe446834c224bd5311e6f1/numpy-2.3.0-cp312-cp312-win_arm64.whl", hash = "sha256:bd8df082b6c4695753ad6193018c05aac465d634834dca47a3ae06d4bb22d9ea", size = 9891498, upload-time = "2025-06-07T14:43:36.332Z" }, + { url = "https://files.pythonhosted.org/packages/73/fc/1d67f751fd4dbafc5780244fe699bc4084268bad44b7c5deb0492473127b/numpy-2.3.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:5754ab5595bfa2c2387d241296e0381c21f44a4b90a776c3c1d39eede13a746a", size = 20889633, upload-time = "2025-06-07T14:44:06.839Z" }, + { url = "https://files.pythonhosted.org/packages/e8/95/73ffdb69e5c3f19ec4530f8924c4386e7ba097efc94b9c0aff607178ad94/numpy-2.3.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:d11fa02f77752d8099573d64e5fe33de3229b6632036ec08f7080f46b6649959", size = 14151683, upload-time = "2025-06-07T14:44:28.847Z" }, + { url = "https://files.pythonhosted.org/packages/64/d5/06d4bb31bb65a1d9c419eb5676173a2f90fd8da3c59f816cc54c640ce265/numpy-2.3.0-cp313-cp313-macosx_14_0_arm64.whl", hash = "sha256:aba48d17e87688a765ab1cd557882052f238e2f36545dfa8e29e6a91aef77afe", size = 5102683, upload-time = "2025-06-07T14:44:38.417Z" }, + { url = "https://files.pythonhosted.org/packages/12/8b/6c2cef44f8ccdc231f6b56013dff1d71138c48124334aded36b1a1b30c5a/numpy-2.3.0-cp313-cp313-macosx_14_0_x86_64.whl", hash = "sha256:4dc58865623023b63b10d52f18abaac3729346a7a46a778381e0e3af4b7f3beb", size = 6640253, upload-time = "2025-06-07T14:44:49.359Z" }, + { url = "https://files.pythonhosted.org/packages/62/aa/fca4bf8de3396ddb59544df9b75ffe5b73096174de97a9492d426f5cd4aa/numpy-2.3.0-cp313-cp313-manylinux_2_28_aarch64.whl", hash = "sha256:df470d376f54e052c76517393fa443758fefcdd634645bc9c1f84eafc67087f0", size = 14258658, upload-time = "2025-06-07T14:45:10.156Z" }, + { url = "https://files.pythonhosted.org/packages/1c/12/734dce1087eed1875f2297f687e671cfe53a091b6f2f55f0c7241aad041b/numpy-2.3.0-cp313-cp313-manylinux_2_28_x86_64.whl", hash = "sha256:87717eb24d4a8a64683b7a4e91ace04e2f5c7c77872f823f02a94feee186168f", size = 16628765, upload-time = "2025-06-07T14:45:35.076Z" }, + { url = "https://files.pythonhosted.org/packages/48/03/ffa41ade0e825cbcd5606a5669962419528212a16082763fc051a7247d76/numpy-2.3.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:d8fa264d56882b59dcb5ea4d6ab6f31d0c58a57b41aec605848b6eb2ef4a43e8", size = 15564335, upload-time = "2025-06-07T14:45:58.797Z" }, + { url = "https://files.pythonhosted.org/packages/07/58/869398a11863310aee0ff85a3e13b4c12f20d032b90c4b3ee93c3b728393/numpy-2.3.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:e651756066a0eaf900916497e20e02fe1ae544187cb0fe88de981671ee7f6270", size = 18360608, upload-time = "2025-06-07T14:46:25.687Z" }, + { url = "https://files.pythonhosted.org/packages/2f/8a/5756935752ad278c17e8a061eb2127c9a3edf4ba2c31779548b336f23c8d/numpy-2.3.0-cp313-cp313-win32.whl", hash = "sha256:e43c3cce3b6ae5f94696669ff2a6eafd9a6b9332008bafa4117af70f4b88be6f", size = 6310005, upload-time = "2025-06-07T14:50:13.138Z" }, + { url = "https://files.pythonhosted.org/packages/08/60/61d60cf0dfc0bf15381eaef46366ebc0c1a787856d1db0c80b006092af84/numpy-2.3.0-cp313-cp313-win_amd64.whl", hash = "sha256:81ae0bf2564cf475f94be4a27ef7bcf8af0c3e28da46770fc904da9abd5279b5", size = 12729093, upload-time = "2025-06-07T14:50:31.82Z" }, + { url = "https://files.pythonhosted.org/packages/66/31/2f2f2d2b3e3c32d5753d01437240feaa32220b73258c9eef2e42a0832866/numpy-2.3.0-cp313-cp313-win_arm64.whl", hash = "sha256:c8738baa52505fa6e82778580b23f945e3578412554d937093eac9205e845e6e", size = 9885689, upload-time = "2025-06-07T14:50:47.888Z" }, + { url = "https://files.pythonhosted.org/packages/f1/89/c7828f23cc50f607ceb912774bb4cff225ccae7131c431398ad8400e2c98/numpy-2.3.0-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:39b27d8b38942a647f048b675f134dd5a567f95bfff481f9109ec308515c51d8", size = 20986612, upload-time = "2025-06-07T14:46:56.077Z" }, + { url = "https://files.pythonhosted.org/packages/dd/46/79ecf47da34c4c50eedec7511e53d57ffdfd31c742c00be7dc1d5ffdb917/numpy-2.3.0-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:0eba4a1ea88f9a6f30f56fdafdeb8da3774349eacddab9581a21234b8535d3d3", size = 14298953, upload-time = "2025-06-07T14:47:18.053Z" }, + { url = "https://files.pythonhosted.org/packages/59/44/f6caf50713d6ff4480640bccb2a534ce1d8e6e0960c8f864947439f0ee95/numpy-2.3.0-cp313-cp313t-macosx_14_0_arm64.whl", hash = "sha256:b0f1f11d0a1da54927436505a5a7670b154eac27f5672afc389661013dfe3d4f", size = 5225806, upload-time = "2025-06-07T14:47:27.524Z" }, + { url = "https://files.pythonhosted.org/packages/a6/43/e1fd1aca7c97e234dd05e66de4ab7a5be54548257efcdd1bc33637e72102/numpy-2.3.0-cp313-cp313t-macosx_14_0_x86_64.whl", hash = "sha256:690d0a5b60a47e1f9dcec7b77750a4854c0d690e9058b7bef3106e3ae9117808", size = 6735169, upload-time = "2025-06-07T14:47:38.057Z" }, + { url = "https://files.pythonhosted.org/packages/84/89/f76f93b06a03177c0faa7ca94d0856c4e5c4bcaf3c5f77640c9ed0303e1c/numpy-2.3.0-cp313-cp313t-manylinux_2_28_aarch64.whl", hash = "sha256:8b51ead2b258284458e570942137155978583e407babc22e3d0ed7af33ce06f8", size = 14330701, upload-time = "2025-06-07T14:47:59.113Z" }, + { url = "https://files.pythonhosted.org/packages/aa/f5/4858c3e9ff7a7d64561b20580cf7cc5d085794bd465a19604945d6501f6c/numpy-2.3.0-cp313-cp313t-manylinux_2_28_x86_64.whl", hash = "sha256:aaf81c7b82c73bd9b45e79cfb9476cb9c29e937494bfe9092c26aece812818ad", size = 16692983, upload-time = "2025-06-07T14:48:24.196Z" }, + { url = "https://files.pythonhosted.org/packages/08/17/0e3b4182e691a10e9483bcc62b4bb8693dbf9ea5dc9ba0b77a60435074bb/numpy-2.3.0-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:f420033a20b4f6a2a11f585f93c843ac40686a7c3fa514060a97d9de93e5e72b", size = 15641435, upload-time = "2025-06-07T14:48:47.712Z" }, + { url = "https://files.pythonhosted.org/packages/4e/d5/463279fda028d3c1efa74e7e8d507605ae87f33dbd0543cf4c4527c8b882/numpy-2.3.0-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:d344ca32ab482bcf8735d8f95091ad081f97120546f3d250240868430ce52555", size = 18433798, upload-time = "2025-06-07T14:49:14.866Z" }, + { url = "https://files.pythonhosted.org/packages/0e/1e/7a9d98c886d4c39a2b4d3a7c026bffcf8fbcaf518782132d12a301cfc47a/numpy-2.3.0-cp313-cp313t-win32.whl", hash = "sha256:48a2e8eaf76364c32a1feaa60d6925eaf32ed7a040183b807e02674305beef61", size = 6438632, upload-time = "2025-06-07T14:49:25.67Z" }, + { url = "https://files.pythonhosted.org/packages/fe/ab/66fc909931d5eb230107d016861824f335ae2c0533f422e654e5ff556784/numpy-2.3.0-cp313-cp313t-win_amd64.whl", hash = "sha256:ba17f93a94e503551f154de210e4d50c5e3ee20f7e7a1b5f6ce3f22d419b93bb", size = 12868491, upload-time = "2025-06-07T14:49:44.898Z" }, + { url = "https://files.pythonhosted.org/packages/ee/e8/2c8a1c9e34d6f6d600c83d5ce5b71646c32a13f34ca5c518cc060639841c/numpy-2.3.0-cp313-cp313t-win_arm64.whl", hash = "sha256:f14e016d9409680959691c109be98c436c6249eaf7f118b424679793607b5944", size = 9935345, upload-time = "2025-06-07T14:50:02.311Z" }, + { url = "https://files.pythonhosted.org/packages/6a/a2/f8c1133f90eaa1c11bbbec1dc28a42054d0ce74bc2c9838c5437ba5d4980/numpy-2.3.0-pp311-pypy311_pp73-macosx_10_15_x86_64.whl", hash = "sha256:80b46117c7359de8167cc00a2c7d823bdd505e8c7727ae0871025a86d668283b", size = 21070759, upload-time = "2025-06-07T14:51:18.241Z" }, + { url = "https://files.pythonhosted.org/packages/6c/e0/4c05fc44ba28463096eee5ae2a12832c8d2759cc5bcec34ae33386d3ff83/numpy-2.3.0-pp311-pypy311_pp73-macosx_14_0_arm64.whl", hash = "sha256:5814a0f43e70c061f47abd5857d120179609ddc32a613138cbb6c4e9e2dbdda5", size = 5301054, upload-time = "2025-06-07T14:51:27.413Z" }, + { url = "https://files.pythonhosted.org/packages/8a/3b/6c06cdebe922bbc2a466fe2105f50f661238ea223972a69c7deb823821e7/numpy-2.3.0-pp311-pypy311_pp73-macosx_14_0_x86_64.whl", hash = "sha256:ef6c1e88fd6b81ac6d215ed71dc8cd027e54d4bf1d2682d362449097156267a2", size = 6817520, upload-time = "2025-06-07T14:51:38.015Z" }, + { url = "https://files.pythonhosted.org/packages/9d/a3/1e536797fd10eb3c5dbd2e376671667c9af19e241843548575267242ea02/numpy-2.3.0-pp311-pypy311_pp73-manylinux_2_28_aarch64.whl", hash = "sha256:33a5a12a45bb82d9997e2c0b12adae97507ad7c347546190a18ff14c28bbca12", size = 14398078, upload-time = "2025-06-07T14:52:00.122Z" }, + { url = "https://files.pythonhosted.org/packages/7c/61/9d574b10d9368ecb1a0c923952aa593510a20df4940aa615b3a71337c8db/numpy-2.3.0-pp311-pypy311_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:54dfc8681c1906d239e95ab1508d0a533c4a9505e52ee2d71a5472b04437ef97", size = 16751324, upload-time = "2025-06-07T14:52:25.077Z" }, + { url = "https://files.pythonhosted.org/packages/39/de/bcad52ce972dc26232629ca3a99721fd4b22c1d2bda84d5db6541913ef9c/numpy-2.3.0-pp311-pypy311_pp73-win_amd64.whl", hash = "sha256:e017a8a251ff4d18d71f139e28bdc7c31edba7a507f72b1414ed902cbe48c74d", size = 12924237, upload-time = "2025-06-07T14:52:44.713Z" }, +] + +[[package]] +name = "packaging" +version = "25.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/a1/d4/1fc4078c65507b51b96ca8f8c3ba19e6a61c8253c72794544580a7b6c24d/packaging-25.0.tar.gz", hash = "sha256:d443872c98d677bf60f6a1f2f8c1cb748e8fe762d2bf9d3148b5599295b0fc4f", size = 165727, upload-time = "2025-04-19T11:48:59.673Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/20/12/38679034af332785aac8774540895e234f4d07f7545804097de4b666afd8/packaging-25.0-py3-none-any.whl", hash = "sha256:29572ef2b1f17581046b3a2227d5c611fb25ec70ca1ba8554b24b0e69331a484", size = 66469, upload-time = "2025-04-19T11:48:57.875Z" }, +] + +[[package]] +name = "pillow" +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" }, + { url = "https://files.pythonhosted.org/packages/1f/e3/0a58b5d838687f40891fff9cbaf8669f90c96b64dc8f91f87894413856c6/pillow-11.2.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b93a07e76d13bff9444f1a029e0af2964e654bfc2e2c2d46bfd080df5ad5f3d8", size = 4498006, upload-time = "2025-04-12T17:47:42.912Z" }, + { url = "https://files.pythonhosted.org/packages/21/f5/6ba14718135f08fbfa33308efe027dd02b781d3f1d5c471444a395933aac/pillow-11.2.1-cp311-cp311-manylinux_2_28_aarch64.whl", hash = "sha256:e6def7eed9e7fa90fde255afaf08060dc4b343bbe524a8f69bdd2a2f0018f600", size = 4517773, upload-time = "2025-04-12T17:47:44.611Z" }, + { url = "https://files.pythonhosted.org/packages/20/f2/805ad600fc59ebe4f1ba6129cd3a75fb0da126975c8579b8f57abeb61e80/pillow-11.2.1-cp311-cp311-manylinux_2_28_x86_64.whl", hash = "sha256:8f4f3724c068be008c08257207210c138d5f3731af6c155a81c2b09a9eb3a788", size = 4607069, upload-time = "2025-04-12T17:47:46.46Z" }, + { url = "https://files.pythonhosted.org/packages/71/6b/4ef8a288b4bb2e0180cba13ca0a519fa27aa982875882392b65131401099/pillow-11.2.1-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:a0a6709b47019dff32e678bc12c63008311b82b9327613f534e496dacaefb71e", size = 4583460, upload-time = "2025-04-12T17:47:49.255Z" }, + { url = "https://files.pythonhosted.org/packages/62/ae/f29c705a09cbc9e2a456590816e5c234382ae5d32584f451c3eb41a62062/pillow-11.2.1-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:f6b0c664ccb879109ee3ca702a9272d877f4fcd21e5eb63c26422fd6e415365e", size = 4661304, upload-time = "2025-04-12T17:47:51.067Z" }, + { url = "https://files.pythonhosted.org/packages/6e/1a/c8217b6f2f73794a5e219fbad087701f412337ae6dbb956db37d69a9bc43/pillow-11.2.1-cp311-cp311-win32.whl", hash = "sha256:cc5d875d56e49f112b6def6813c4e3d3036d269c008bf8aef72cd08d20ca6df6", size = 2331809, upload-time = "2025-04-12T17:47:54.425Z" }, + { url = "https://files.pythonhosted.org/packages/e2/72/25a8f40170dc262e86e90f37cb72cb3de5e307f75bf4b02535a61afcd519/pillow-11.2.1-cp311-cp311-win_amd64.whl", hash = "sha256:0f5c7eda47bf8e3c8a283762cab94e496ba977a420868cb819159980b6709193", size = 2676338, upload-time = "2025-04-12T17:47:56.535Z" }, + { url = "https://files.pythonhosted.org/packages/06/9e/76825e39efee61efea258b479391ca77d64dbd9e5804e4ad0fa453b4ba55/pillow-11.2.1-cp311-cp311-win_arm64.whl", hash = "sha256:4d375eb838755f2528ac8cbc926c3e31cc49ca4ad0cf79cff48b20e30634a4a7", size = 2414918, upload-time = "2025-04-12T17:47:58.217Z" }, + { url = "https://files.pythonhosted.org/packages/c7/40/052610b15a1b8961f52537cc8326ca6a881408bc2bdad0d852edeb6ed33b/pillow-11.2.1-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:78afba22027b4accef10dbd5eed84425930ba41b3ea0a86fa8d20baaf19d807f", size = 3190185, upload-time = "2025-04-12T17:48:00.417Z" }, + { url = "https://files.pythonhosted.org/packages/e5/7e/b86dbd35a5f938632093dc40d1682874c33dcfe832558fc80ca56bfcb774/pillow-11.2.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:78092232a4ab376a35d68c4e6d5e00dfd73454bd12b230420025fbe178ee3b0b", size = 3030306, upload-time = "2025-04-12T17:48:02.391Z" }, + { url = "https://files.pythonhosted.org/packages/a4/5c/467a161f9ed53e5eab51a42923c33051bf8d1a2af4626ac04f5166e58e0c/pillow-11.2.1-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:25a5f306095c6780c52e6bbb6109624b95c5b18e40aab1c3041da3e9e0cd3e2d", size = 4416121, upload-time = "2025-04-12T17:48:04.554Z" }, + { url = "https://files.pythonhosted.org/packages/62/73/972b7742e38ae0e2ac76ab137ca6005dcf877480da0d9d61d93b613065b4/pillow-11.2.1-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0c7b29dbd4281923a2bfe562acb734cee96bbb129e96e6972d315ed9f232bef4", size = 4501707, upload-time = "2025-04-12T17:48:06.831Z" }, + { url = "https://files.pythonhosted.org/packages/e4/3a/427e4cb0b9e177efbc1a84798ed20498c4f233abde003c06d2650a6d60cb/pillow-11.2.1-cp312-cp312-manylinux_2_28_aarch64.whl", hash = "sha256:3e645b020f3209a0181a418bffe7b4a93171eef6c4ef6cc20980b30bebf17b7d", size = 4522921, upload-time = "2025-04-12T17:48:09.229Z" }, + { url = "https://files.pythonhosted.org/packages/fe/7c/d8b1330458e4d2f3f45d9508796d7caf0c0d3764c00c823d10f6f1a3b76d/pillow-11.2.1-cp312-cp312-manylinux_2_28_x86_64.whl", hash = "sha256:b2dbea1012ccb784a65349f57bbc93730b96e85b42e9bf7b01ef40443db720b4", size = 4612523, upload-time = "2025-04-12T17:48:11.631Z" }, + { url = "https://files.pythonhosted.org/packages/b3/2f/65738384e0b1acf451de5a573d8153fe84103772d139e1e0bdf1596be2ea/pillow-11.2.1-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:da3104c57bbd72948d75f6a9389e6727d2ab6333c3617f0a89d72d4940aa0443", size = 4587836, upload-time = "2025-04-12T17:48:13.592Z" }, + { url = "https://files.pythonhosted.org/packages/6a/c5/e795c9f2ddf3debb2dedd0df889f2fe4b053308bb59a3cc02a0cd144d641/pillow-11.2.1-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:598174aef4589af795f66f9caab87ba4ff860ce08cd5bb447c6fc553ffee603c", size = 4669390, upload-time = "2025-04-12T17:48:15.938Z" }, + { url = "https://files.pythonhosted.org/packages/96/ae/ca0099a3995976a9fce2f423166f7bff9b12244afdc7520f6ed38911539a/pillow-11.2.1-cp312-cp312-win32.whl", hash = "sha256:1d535df14716e7f8776b9e7fee118576d65572b4aad3ed639be9e4fa88a1cad3", size = 2332309, upload-time = "2025-04-12T17:48:17.885Z" }, + { url = "https://files.pythonhosted.org/packages/7c/18/24bff2ad716257fc03da964c5e8f05d9790a779a8895d6566e493ccf0189/pillow-11.2.1-cp312-cp312-win_amd64.whl", hash = "sha256:14e33b28bf17c7a38eede290f77db7c664e4eb01f7869e37fa98a5aa95978941", size = 2676768, upload-time = "2025-04-12T17:48:19.655Z" }, + { url = "https://files.pythonhosted.org/packages/da/bb/e8d656c9543276517ee40184aaa39dcb41e683bca121022f9323ae11b39d/pillow-11.2.1-cp312-cp312-win_arm64.whl", hash = "sha256:21e1470ac9e5739ff880c211fc3af01e3ae505859392bf65458c224d0bf283eb", size = 2415087, upload-time = "2025-04-12T17:48:21.991Z" }, + { url = "https://files.pythonhosted.org/packages/36/9c/447528ee3776e7ab8897fe33697a7ff3f0475bb490c5ac1456a03dc57956/pillow-11.2.1-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:fdec757fea0b793056419bca3e9932eb2b0ceec90ef4813ea4c1e072c389eb28", size = 3190098, upload-time = "2025-04-12T17:48:23.915Z" }, + { url = "https://files.pythonhosted.org/packages/b5/09/29d5cd052f7566a63e5b506fac9c60526e9ecc553825551333e1e18a4858/pillow-11.2.1-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:b0e130705d568e2f43a17bcbe74d90958e8a16263868a12c3e0d9c8162690830", size = 3030166, upload-time = "2025-04-12T17:48:25.738Z" }, + { url = "https://files.pythonhosted.org/packages/71/5d/446ee132ad35e7600652133f9c2840b4799bbd8e4adba881284860da0a36/pillow-11.2.1-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:7bdb5e09068332578214cadd9c05e3d64d99e0e87591be22a324bdbc18925be0", size = 4408674, upload-time = "2025-04-12T17:48:27.908Z" }, + { url = "https://files.pythonhosted.org/packages/69/5f/cbe509c0ddf91cc3a03bbacf40e5c2339c4912d16458fcb797bb47bcb269/pillow-11.2.1-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d189ba1bebfbc0c0e529159631ec72bb9e9bc041f01ec6d3233d6d82eb823bc1", size = 4496005, upload-time = "2025-04-12T17:48:29.888Z" }, + { url = "https://files.pythonhosted.org/packages/f9/b3/dd4338d8fb8a5f312021f2977fb8198a1184893f9b00b02b75d565c33b51/pillow-11.2.1-cp313-cp313-manylinux_2_28_aarch64.whl", hash = "sha256:191955c55d8a712fab8934a42bfefbf99dd0b5875078240943f913bb66d46d9f", size = 4518707, upload-time = "2025-04-12T17:48:31.874Z" }, + { url = "https://files.pythonhosted.org/packages/13/eb/2552ecebc0b887f539111c2cd241f538b8ff5891b8903dfe672e997529be/pillow-11.2.1-cp313-cp313-manylinux_2_28_x86_64.whl", hash = "sha256:ad275964d52e2243430472fc5d2c2334b4fc3ff9c16cb0a19254e25efa03a155", size = 4610008, upload-time = "2025-04-12T17:48:34.422Z" }, + { url = "https://files.pythonhosted.org/packages/72/d1/924ce51bea494cb6e7959522d69d7b1c7e74f6821d84c63c3dc430cbbf3b/pillow-11.2.1-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:750f96efe0597382660d8b53e90dd1dd44568a8edb51cb7f9d5d918b80d4de14", size = 4585420, upload-time = "2025-04-12T17:48:37.641Z" }, + { url = "https://files.pythonhosted.org/packages/43/ab/8f81312d255d713b99ca37479a4cb4b0f48195e530cdc1611990eb8fd04b/pillow-11.2.1-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:fe15238d3798788d00716637b3d4e7bb6bde18b26e5d08335a96e88564a36b6b", size = 4667655, upload-time = "2025-04-12T17:48:39.652Z" }, + { url = "https://files.pythonhosted.org/packages/94/86/8f2e9d2dc3d308dfd137a07fe1cc478df0a23d42a6c4093b087e738e4827/pillow-11.2.1-cp313-cp313-win32.whl", hash = "sha256:3fe735ced9a607fee4f481423a9c36701a39719252a9bb251679635f99d0f7d2", size = 2332329, upload-time = "2025-04-12T17:48:41.765Z" }, + { url = "https://files.pythonhosted.org/packages/6d/ec/1179083b8d6067a613e4d595359b5fdea65d0a3b7ad623fee906e1b3c4d2/pillow-11.2.1-cp313-cp313-win_amd64.whl", hash = "sha256:74ee3d7ecb3f3c05459ba95eed5efa28d6092d751ce9bf20e3e253a4e497e691", size = 2676388, upload-time = "2025-04-12T17:48:43.625Z" }, + { url = "https://files.pythonhosted.org/packages/23/f1/2fc1e1e294de897df39fa8622d829b8828ddad938b0eaea256d65b84dd72/pillow-11.2.1-cp313-cp313-win_arm64.whl", hash = "sha256:5119225c622403afb4b44bad4c1ca6c1f98eed79db8d3bc6e4e160fc6339d66c", size = 2414950, upload-time = "2025-04-12T17:48:45.475Z" }, + { url = "https://files.pythonhosted.org/packages/c4/3e/c328c48b3f0ead7bab765a84b4977acb29f101d10e4ef57a5e3400447c03/pillow-11.2.1-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:8ce2e8411c7aaef53e6bb29fe98f28cd4fbd9a1d9be2eeea434331aac0536b22", size = 3192759, upload-time = "2025-04-12T17:48:47.866Z" }, + { url = "https://files.pythonhosted.org/packages/18/0e/1c68532d833fc8b9f404d3a642991441d9058eccd5606eab31617f29b6d4/pillow-11.2.1-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:9ee66787e095127116d91dea2143db65c7bb1e232f617aa5957c0d9d2a3f23a7", size = 3033284, upload-time = "2025-04-12T17:48:50.189Z" }, + { url = "https://files.pythonhosted.org/packages/b7/cb/6faf3fb1e7705fd2db74e070f3bf6f88693601b0ed8e81049a8266de4754/pillow-11.2.1-cp313-cp313t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:9622e3b6c1d8b551b6e6f21873bdcc55762b4b2126633014cea1803368a9aa16", size = 4445826, upload-time = "2025-04-12T17:48:52.346Z" }, + { url = "https://files.pythonhosted.org/packages/07/94/8be03d50b70ca47fb434a358919d6a8d6580f282bbb7af7e4aa40103461d/pillow-11.2.1-cp313-cp313t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:63b5dff3a68f371ea06025a1a6966c9a1e1ee452fc8020c2cd0ea41b83e9037b", size = 4527329, upload-time = "2025-04-12T17:48:54.403Z" }, + { url = "https://files.pythonhosted.org/packages/fd/a4/bfe78777076dc405e3bd2080bc32da5ab3945b5a25dc5d8acaa9de64a162/pillow-11.2.1-cp313-cp313t-manylinux_2_28_aarch64.whl", hash = "sha256:31df6e2d3d8fc99f993fd253e97fae451a8db2e7207acf97859732273e108406", size = 4549049, upload-time = "2025-04-12T17:48:56.383Z" }, + { url = "https://files.pythonhosted.org/packages/65/4d/eaf9068dc687c24979e977ce5677e253624bd8b616b286f543f0c1b91662/pillow-11.2.1-cp313-cp313t-manylinux_2_28_x86_64.whl", hash = "sha256:062b7a42d672c45a70fa1f8b43d1d38ff76b63421cbbe7f88146b39e8a558d91", size = 4635408, upload-time = "2025-04-12T17:48:58.782Z" }, + { url = "https://files.pythonhosted.org/packages/1d/26/0fd443365d9c63bc79feb219f97d935cd4b93af28353cba78d8e77b61719/pillow-11.2.1-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:4eb92eca2711ef8be42fd3f67533765d9fd043b8c80db204f16c8ea62ee1a751", size = 4614863, upload-time = "2025-04-12T17:49:00.709Z" }, + { url = "https://files.pythonhosted.org/packages/49/65/dca4d2506be482c2c6641cacdba5c602bc76d8ceb618fd37de855653a419/pillow-11.2.1-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:f91ebf30830a48c825590aede79376cb40f110b387c17ee9bd59932c961044f9", size = 4692938, upload-time = "2025-04-12T17:49:02.946Z" }, + { 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" }, + { url = "https://files.pythonhosted.org/packages/9d/8f/abd47b73c60712f88e9eda32baced7bfc3e9bd6a7619bb64b93acff28c3e/pillow-11.2.1-pp311-pypy311_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9db98ab6565c69082ec9b0d4e40dd9f6181dab0dd236d26f7a50b8b9bfbd5076", size = 3460013, upload-time = "2025-04-12T17:49:53.278Z" }, + { url = "https://files.pythonhosted.org/packages/f6/20/5c0a0aa83b213b7a07ec01e71a3d6ea2cf4ad1d2c686cc0168173b6089e7/pillow-11.2.1-pp311-pypy311_pp73-manylinux_2_28_aarch64.whl", hash = "sha256:036e53f4170e270ddb8797d4c590e6dd14d28e15c7da375c18978045f7e6c37b", size = 3527165, upload-time = "2025-04-12T17:49:55.164Z" }, + { url = "https://files.pythonhosted.org/packages/58/0e/2abab98a72202d91146abc839e10c14f7cf36166f12838ea0c4db3ca6ecb/pillow-11.2.1-pp311-pypy311_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:14f73f7c291279bd65fda51ee87affd7c1e097709f7fdd0188957a16c264601f", size = 3571586, upload-time = "2025-04-12T17:49:57.171Z" }, + { url = "https://files.pythonhosted.org/packages/21/2c/5e05f58658cf49b6667762cca03d6e7d85cededde2caf2ab37b81f80e574/pillow-11.2.1-pp311-pypy311_pp73-win_amd64.whl", hash = "sha256:208653868d5c9ecc2b327f9b9ef34e0e42a4cdd172c2988fd81d62d2bc9bc044", size = 2674751, upload-time = "2025-04-12T17:49:59.628Z" }, +] + +[[package]] +name = "platformdirs" +version = "4.3.8" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/fe/8b/3c73abc9c759ecd3f1f7ceff6685840859e8070c4d947c93fae71f6a0bf2/platformdirs-4.3.8.tar.gz", hash = "sha256:3d512d96e16bcb959a814c9f348431070822a6496326a4be0911c40b5a74c2bc", size = 21362, upload-time = "2025-05-07T22:47:42.121Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/fe/39/979e8e21520d4e47a0bbe349e2713c0aac6f3d853d0e5b34d76206c439aa/platformdirs-4.3.8-py3-none-any.whl", hash = "sha256:ff7059bb7eb1179e2685604f4aaf157cfd9535242bd23742eadc3c13542139b4", size = 18567, upload-time = "2025-05-07T22:47:40.376Z" }, +] + +[[package]] +name = "pre-commit" +version = "4.2.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "cfgv" }, + { name = "identify" }, + { name = "nodeenv" }, + { name = "pyyaml" }, + { name = "virtualenv" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/08/39/679ca9b26c7bb2999ff122d50faa301e49af82ca9c066ec061cfbc0c6784/pre_commit-4.2.0.tar.gz", hash = "sha256:601283b9757afd87d40c4c4a9b2b5de9637a8ea02eaff7adc2d0fb4e04841146", size = 193424, upload-time = "2025-03-18T21:35:20.987Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/88/74/a88bf1b1efeae488a0c0b7bdf71429c313722d1fc0f377537fbe554e6180/pre_commit-4.2.0-py2.py3-none-any.whl", hash = "sha256:a009ca7205f1eb497d10b845e52c838a98b6cdd2102a6c8e4540e94ee75c58bd", size = 220707, upload-time = "2025-03-18T21:35:19.343Z" }, +] + +[[package]] +name = "pycparser" +version = "2.22" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/1d/b2/31537cf4b1ca988837256c910a668b553fceb8f069bedc4b1c826024b52c/pycparser-2.22.tar.gz", hash = "sha256:491c8be9c040f5390f5bf44a5b07752bd07f56edf992381b05c701439eec10f6", size = 172736, upload-time = "2024-03-30T13:22:22.564Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/13/a3/a812df4e2dd5696d1f351d58b8fe16a405b234ad2886a0dab9183fb78109/pycparser-2.22-py3-none-any.whl", hash = "sha256:c3702b6d3dd8c7abc1afa565d7e63d53a1d0bd86cdc24edd75470f4de499cfcc", size = 117552, upload-time = "2024-03-30T13:22:20.476Z" }, +] + +[[package]] +name = "pyds9" +version = "1.8.1" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "six" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/c2/cb/b9a20a6479a44eb9bbc2cb313469feed3da94707f325195dee2d6ca491bd/pyds9-1.8.1.tar.gz", hash = "sha256:b4f198f5d29b749f721c491f8384f6293e43ec417bd0492be36bffb5c3904b2a", size = 888357, upload-time = "2016-08-05T02:19:16.256Z" } + +[[package]] +name = "pyerfa" +version = "2.0.1.5" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "numpy", version = "2.2.6", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version < '3.11'" }, + { name = "numpy", version = "2.3.0", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.11'" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/71/39/63cc8291b0cf324ae710df41527faf7d331bce573899199d926b3e492260/pyerfa-2.0.1.5.tar.gz", hash = "sha256:17d6b24fe4846c65d5e7d8c362dcb08199dc63b30a236aedd73875cc83e1f6c0", size = 818430, upload-time = "2024-11-11T15:22:30.852Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/7d/d9/3448a57cb5bd19950de6d6ab08bd8fbb3df60baa71726de91d73d76c481b/pyerfa-2.0.1.5-cp39-abi3-macosx_10_9_x86_64.whl", hash = "sha256:b282d7c60c4c47cf629c484c17ac504fcb04abd7b3f4dfcf53ee042afc3a5944", size = 341818, upload-time = "2024-11-11T15:22:16.467Z" }, + { url = "https://files.pythonhosted.org/packages/11/4a/31a363370478b63c6289a34743f2ba2d3ae1bd8223e004d18ab28fb92385/pyerfa-2.0.1.5-cp39-abi3-macosx_11_0_arm64.whl", hash = "sha256:be1aeb70390dd03a34faf96749d5cabc58437410b4aab7213c512323932427df", size = 329370, upload-time = "2024-11-11T15:22:17.829Z" }, + { url = "https://files.pythonhosted.org/packages/cb/96/b6210fc624123c8ae13e1eecb68fb75e3f3adff216d95eee1c7b05843e3e/pyerfa-2.0.1.5-cp39-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b0603e8e1b839327d586c8a627cdc634b795e18b007d84f0cda5500a0908254e", size = 692794, upload-time = "2024-11-11T15:22:19.429Z" }, + { url = "https://files.pythonhosted.org/packages/e5/e0/050018d855d26d3c0b4a7d1b2ed692be758ce276d8289e2a2b44ba1014a5/pyerfa-2.0.1.5-cp39-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0e43c7194e3242083f2350b46c09fd4bf8ba1bcc0ebd1460b98fc47fe2389906", size = 738711, upload-time = "2024-11-11T15:22:20.661Z" }, + { url = "https://files.pythonhosted.org/packages/b9/f5/ff91ee77308793ae32fa1e1de95e9edd4551456dd888b4e87c5938657ca5/pyerfa-2.0.1.5-cp39-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:07b80cd70701f5d066b1ac8cce406682cfcd667a1186ec7d7ade597239a6021d", size = 722966, upload-time = "2024-11-11T15:22:21.905Z" }, + { url = "https://files.pythonhosted.org/packages/2c/56/b22b35c8551d2228ff8d445e63787112927ca13f6dc9e2c04f69d742c95b/pyerfa-2.0.1.5-cp39-abi3-win32.whl", hash = "sha256:d30b9b0df588ed5467e529d851ea324a67239096dd44703125072fd11b351ea2", size = 339955, upload-time = "2024-11-11T15:22:23.087Z" }, + { url = "https://files.pythonhosted.org/packages/b4/11/97233cf23ad5411ac6f13b1d6ee3888f90ace4f974d9bf9db887aa428912/pyerfa-2.0.1.5-cp39-abi3-win_amd64.whl", hash = "sha256:66292d437dcf75925b694977aa06eb697126e7b86553e620371ed3e48b5e0ad0", size = 349410, upload-time = "2024-11-11T15:22:24.817Z" }, +] + +[[package]] +name = "pyparsing" +version = "3.2.3" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/bb/22/f1129e69d94ffff626bdb5c835506b3a5b4f3d070f17ea295e12c2c6f60f/pyparsing-3.2.3.tar.gz", hash = "sha256:b9c13f1ab8b3b542f72e28f634bad4de758ab3ce4546e4301970ad6fa77c38be", size = 1088608, upload-time = "2025-03-25T05:01:28.114Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/05/e7/df2285f3d08fee213f2d041540fa4fc9ca6c2d44cf36d3a035bf2a8d2bcc/pyparsing-3.2.3-py3-none-any.whl", hash = "sha256:a749938e02d6fd0b59b356ca504a24982314bb090c383e3cf201c95ef7e2bfcf", size = 111120, upload-time = "2025-03-25T05:01:24.908Z" }, +] + +[[package]] +name = "pypdf" +version = "5.6.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "typing-extensions", marker = "python_full_version < '3.11'" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/40/46/67de1d7a65412aa1c896e6b280829b70b57d203fadae6859b690006b8e0a/pypdf-5.6.0.tar.gz", hash = "sha256:a4b6538b77fc796622000db7127e4e58039ec5e6afd292f8e9bf42e2e985a749", size = 5023749, upload-time = "2025-06-01T12:19:40.101Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/71/8b/dc3a72d98c22be7a4cbd664ad14c5a3e6295c2dbdf572865ed61e24b5e38/pypdf-5.6.0-py3-none-any.whl", hash = "sha256:ca6bf446bfb0a2d8d71d6d6bb860798d864c36a29b3d9ae8d7fc7958c59f88e7", size = 304208, upload-time = "2025-06-01T12:19:38.003Z" }, +] + +[[package]] +name = "pyqt5" +version = "5.15.11" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "pyqt5-qt5" }, + { name = "pyqt5-sip" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/0e/07/c9ed0bd428df6f87183fca565a79fee19fa7c88c7f00a7f011ab4379e77a/PyQt5-5.15.11.tar.gz", hash = "sha256:fda45743ebb4a27b4b1a51c6d8ef455c4c1b5d610c90d2934c7802b5c1557c52", size = 3216775, upload-time = "2024-07-19T08:39:57.756Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/11/64/42ec1b0bd72d87f87bde6ceb6869f444d91a2d601f2e67cd05febc0346a1/PyQt5-5.15.11-cp38-abi3-macosx_11_0_arm64.whl", hash = "sha256:c8b03dd9380bb13c804f0bdb0f4956067f281785b5e12303d529f0462f9afdc2", size = 6579776, upload-time = "2024-07-19T08:39:19.775Z" }, + { url = "https://files.pythonhosted.org/packages/49/f5/3fb696f4683ea45d68b7e77302eff173493ac81e43d63adb60fa760b9f91/PyQt5-5.15.11-cp38-abi3-macosx_11_0_x86_64.whl", hash = "sha256:6cd75628f6e732b1ffcfe709ab833a0716c0445d7aec8046a48d5843352becb6", size = 7016415, upload-time = "2024-07-19T08:39:32.977Z" }, + { url = "https://files.pythonhosted.org/packages/b4/8c/4065950f9d013c4b2e588fe33cf04e564c2322842d84dbcbce5ba1dc28b0/PyQt5-5.15.11-cp38-abi3-manylinux_2_17_x86_64.whl", hash = "sha256:cd672a6738d1ae33ef7d9efa8e6cb0a1525ecf53ec86da80a9e1b6ec38c8d0f1", size = 8188103, upload-time = "2024-07-19T08:39:40.561Z" }, + { url = "https://files.pythonhosted.org/packages/f3/f0/ae5a5b4f9b826b29ea4be841b2f2d951bcf5ae1d802f3732b145b57c5355/PyQt5-5.15.11-cp38-abi3-win32.whl", hash = "sha256:76be0322ceda5deecd1708a8d628e698089a1cea80d1a49d242a6d579a40babd", size = 5433308, upload-time = "2024-07-19T08:39:46.932Z" }, + { url = "https://files.pythonhosted.org/packages/56/d5/68eb9f3d19ce65df01b6c7b7a577ad3bbc9ab3a5dd3491a4756e71838ec9/PyQt5-5.15.11-cp38-abi3-win_amd64.whl", hash = "sha256:bdde598a3bb95022131a5c9ea62e0a96bd6fb28932cc1619fd7ba211531b7517", size = 6865864, upload-time = "2024-07-19T08:39:53.572Z" }, +] + +[[package]] +name = "pyqt5-qt5" +version = "5.15.17" +source = { registry = "https://pypi.org/simple" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/d3/f9/accb06e76e23fb23053d48cc24fd78dec6ed14cb4d5cbadb0fd4a0c1b02e/PyQt5_Qt5-5.15.17-py3-none-macosx_10_13_x86_64.whl", hash = "sha256:d8b8094108e748b4bbd315737cfed81291d2d228de43278f0b8bd7d2b808d2b9", size = 39972275, upload-time = "2025-05-24T11:15:42.259Z" }, + { url = "https://files.pythonhosted.org/packages/87/1a/e1601ad6934cc489b8f1e967494f23958465cf1943712f054c5a306e9029/PyQt5_Qt5-5.15.17-py3-none-macosx_11_0_arm64.whl", hash = "sha256:b68628f9b8261156f91d2f72ebc8dfb28697c4b83549245d9a68195bd2d74f0c", size = 37135109, upload-time = "2025-05-24T11:15:59.786Z" }, + { url = "https://files.pythonhosted.org/packages/ac/e1/13d25a9ff2ac236a264b4603abaa39fa8bb9a7aa430519bb5f545c5b008d/PyQt5_Qt5-5.15.17-py3-none-manylinux2014_x86_64.whl", hash = "sha256:b018f75d1cc61146396fa5af14da1db77c5d6318030e5e366f09ffdf7bd358d8", size = 61112954, upload-time = "2025-05-24T11:16:26.036Z" }, +] + +[[package]] +name = "pyqt5-sip" +version = "12.17.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/01/79/086b50414bafa71df494398ad277d72e58229a3d1c1b1c766d12b14c2e6d/pyqt5_sip-12.17.0.tar.gz", hash = "sha256:682dadcdbd2239af9fdc0c0628e2776b820e128bec88b49b8d692fe682f90b4f", size = 104042, upload-time = "2025-02-02T17:13:11.268Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/6b/23/1da570b7e143b6d216728c919cae2976f7dbff65db94e3d9f5b62df37ba5/PyQt5_sip-12.17.0-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:ec47914cc751608e587c1c2fdabeaf4af7fdc28b9f62796c583bea01c1a1aa3e", size = 122696, upload-time = "2025-02-02T17:12:35.786Z" }, + { url = "https://files.pythonhosted.org/packages/61/d5/506b1c3ad06268c601276572f1cde1c0dffd074b44e023f4d80f5ea49265/PyQt5_sip-12.17.0-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:2f2a8dcc7626fe0da73a0918e05ce2460c7a14ddc946049310e6e35052105434", size = 270932, upload-time = "2025-02-02T17:12:38.175Z" }, + { url = "https://files.pythonhosted.org/packages/0b/9b/46159d8038374b076244a1930ead460e723453ec73f9b0330390ddfdd0ea/PyQt5_sip-12.17.0-cp310-cp310-win32.whl", hash = "sha256:0c75d28b8282be3c1d7dbc76950d6e6eba1e334783224e9b9835ce1a9c64f482", size = 49085, upload-time = "2025-02-02T17:12:40.146Z" }, + { url = "https://files.pythonhosted.org/packages/fe/66/b3eb937a620ce2a5db5c377beeca870d60fafd87aecc1bcca6921bbcf553/PyQt5_sip-12.17.0-cp310-cp310-win_amd64.whl", hash = "sha256:8c4bc535bae0dfa764e8534e893619fe843ce5a2e25f901c439bcb960114f686", size = 59040, upload-time = "2025-02-02T17:12:41.962Z" }, + { url = "https://files.pythonhosted.org/packages/52/fd/7d6e3deca5ce37413956faf4e933ce6beb87ac0cc7b26d934b5ed998f88a/PyQt5_sip-12.17.0-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:2c912807dd638644168ea8c7a447bfd9d85a19471b98c2c588c4d2e911c09b0a", size = 122748, upload-time = "2025-02-02T17:12:43.831Z" }, + { url = "https://files.pythonhosted.org/packages/29/4d/e5981cde03b091fd83a1ef4ef6a4ca99ce6921d61b80c0222fc8eafdc99a/PyQt5_sip-12.17.0-cp311-cp311-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:71514a7d43b44faa1d65a74ad2c5da92c03a251bdc749f009c313f06cceacc9a", size = 276401, upload-time = "2025-02-02T17:12:45.705Z" }, + { url = "https://files.pythonhosted.org/packages/5f/30/4c282896b1e8841639cf2aca59acf57d8b261ed834ae976c959f25fa4a35/PyQt5_sip-12.17.0-cp311-cp311-win32.whl", hash = "sha256:023466ae96f72fbb8419b44c3f97475de6642fa5632520d0f50fc1a52a3e8200", size = 49091, upload-time = "2025-02-02T17:12:47.688Z" }, + { url = "https://files.pythonhosted.org/packages/24/c1/50fc7301aa39a50f451fc1b6b219e778c540a823fe9533a57b4793c859fd/PyQt5_sip-12.17.0-cp311-cp311-win_amd64.whl", hash = "sha256:fb565469d08dcb0a427def0c45e722323beb62db79454260482b6948bfd52d47", size = 59036, upload-time = "2025-02-02T17:12:49.535Z" }, + { url = "https://files.pythonhosted.org/packages/a3/e6/e51367c28d69b5a462f38987f6024e766fd8205f121fe2f4d8ba2a6886b9/PyQt5_sip-12.17.0-cp312-cp312-macosx_10_9_universal2.whl", hash = "sha256:ea08341c8a5da00c81df0d689ecd4ee47a95e1ecad9e362581c92513f2068005", size = 124650, upload-time = "2025-02-02T17:12:50.595Z" }, + { url = "https://files.pythonhosted.org/packages/64/3b/e6d1f772b41d8445d6faf86cc9da65910484ebd9f7df83abc5d4955437d0/PyQt5_sip-12.17.0-cp312-cp312-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:4a92478d6808040fbe614bb61500fbb3f19f72714b99369ec28d26a7e3494115", size = 281893, upload-time = "2025-02-02T17:12:51.966Z" }, + { url = "https://files.pythonhosted.org/packages/ed/c5/d17fc2ddb9156a593710c88afd98abcf4055a2224b772f8bec2c6eea879c/PyQt5_sip-12.17.0-cp312-cp312-win32.whl", hash = "sha256:b0ff280b28813e9bfd3a4de99490739fc29b776dc48f1c849caca7239a10fc8b", size = 49438, upload-time = "2025-02-02T17:12:54.426Z" }, + { url = "https://files.pythonhosted.org/packages/fe/c5/1174988d52c732d07033cf9a5067142b01d76be7731c6394a64d5c3ef65c/PyQt5_sip-12.17.0-cp312-cp312-win_amd64.whl", hash = "sha256:54c31de7706d8a9a8c0fc3ea2c70468aba54b027d4974803f8eace9c22aad41c", size = 58017, upload-time = "2025-02-02T17:12:56.31Z" }, + { url = "https://files.pythonhosted.org/packages/fd/5d/f234e505af1a85189310521447ebc6052ebb697efded850d0f2b2555f7aa/PyQt5_sip-12.17.0-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:c7a7ff355e369616b6bcb41d45b742327c104b2bf1674ec79b8d67f8f2fa9543", size = 124580, upload-time = "2025-02-02T17:12:58.158Z" }, + { url = "https://files.pythonhosted.org/packages/cd/cb/3b2050e9644d0021bdf25ddf7e4c3526e1edd0198879e76ba308e5d44faf/PyQt5_sip-12.17.0-cp313-cp313-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:419b9027e92b0b707632c370cfc6dc1f3b43c6313242fc4db57a537029bd179c", size = 281563, upload-time = "2025-02-02T17:12:59.421Z" }, + { url = "https://files.pythonhosted.org/packages/51/61/b8ebde7e0b32d0de44c521a0ace31439885b0423d7d45d010a2f7d92808c/PyQt5_sip-12.17.0-cp313-cp313-win32.whl", hash = "sha256:351beab964a19f5671b2a3e816ecf4d3543a99a7e0650f88a947fea251a7589f", size = 49383, upload-time = "2025-02-02T17:13:00.597Z" }, + { url = "https://files.pythonhosted.org/packages/15/ed/ff94d6b2910e7627380cb1fc9a518ff966e6d78285c8e54c9422b68305db/PyQt5_sip-12.17.0-cp313-cp313-win_amd64.whl", hash = "sha256:672c209d05661fab8e17607c193bf43991d268a1eefbc2c4551fbf30fd8bb2ca", size = 58022, upload-time = "2025-02-02T17:13:01.738Z" }, +] + +[[package]] +name = "pysas" +version = "1.4.7" +source = { virtual = "." } +dependencies = [ + { name = "astropy", version = "6.1.7", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version < '3.11'" }, + { name = "astropy", version = "7.1.0", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.11'" }, + { name = "astroquery" }, + { name = "beautifultable" }, + { name = "loguru" }, + { name = "matplotlib" }, + { name = "pre-commit" }, + { name = "pyds9" }, + { name = "pypdf" }, + { name = "pyqt5" }, + { name = "scipy" }, +] + +[package.metadata] +requires-dist = [ + { name = "astropy", specifier = ">=6.1.7" }, + { name = "astroquery", specifier = ">=0.4.10" }, + { name = "beautifultable", specifier = ">=1.1.0" }, + { name = "loguru", specifier = ">=0.7.3" }, + { name = "matplotlib", specifier = ">=3.10.3" }, + { name = "pre-commit", specifier = ">=4.2.0" }, + { name = "pyds9", specifier = ">=1.8.1" }, + { name = "pypdf", specifier = ">=5.6.0" }, + { name = "pyqt5", specifier = ">=5.15.11" }, + { name = "scipy", specifier = ">=1.15.3" }, +] + +[[package]] +name = "python-dateutil" +version = "2.9.0.post0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "six" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/66/c0/0c8b6ad9f17a802ee498c46e004a0eb49bc148f2fd230864601a86dcf6db/python-dateutil-2.9.0.post0.tar.gz", hash = "sha256:37dd54208da7e1cd875388217d5e00ebd4179249f90fb72437e91a35459a0ad3", size = 342432, upload-time = "2024-03-01T18:36:20.211Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/ec/57/56b9bcc3c9c6a792fcbaf139543cee77261f3651ca9da0c93f5c1221264b/python_dateutil-2.9.0.post0-py2.py3-none-any.whl", hash = "sha256:a8b2bc7bffae282281c8140a97d3aa9c14da0b136dfe83f850eea9a5f7470427", size = 229892, upload-time = "2024-03-01T18:36:18.57Z" }, +] + +[[package]] +name = "pyvo" +version = "1.7" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "astropy", version = "6.1.7", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version < '3.11'" }, + { name = "astropy", version = "7.1.0", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.11'" }, + { name = "requests" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/b6/27/e5cec6dea4bfe4e4e6819bd940bd74edbc5b168be7cd15fbf0a0712a3995/pyvo-1.7.tar.gz", hash = "sha256:a6fad9efd410732d113e55df43b0201c9acb2e29f27532c71bda56f38ce62320", size = 2095584, upload-time = "2025-06-02T03:06:01.788Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/b0/7a/1e561c455e2618617d906f1d09724b92059b882fd529f0cd4ca0408ccaea/pyvo-1.7-py3-none-any.whl", hash = "sha256:f1019a7f62cd0ba8d61908d4cc2b4d2b37410a7d75401ef9cdf7dbc99d232434", size = 1075136, upload-time = "2025-06-02T03:05:58.543Z" }, +] + +[[package]] +name = "pywin32-ctypes" +version = "0.2.3" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/85/9f/01a1a99704853cb63f253eea009390c88e7131c67e66a0a02099a8c917cb/pywin32-ctypes-0.2.3.tar.gz", hash = "sha256:d162dc04946d704503b2edc4d55f3dba5c1d539ead017afa00142c38b9885755", size = 29471, upload-time = "2024-08-14T10:15:34.626Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/de/3d/8161f7711c017e01ac9f008dfddd9410dff3674334c233bde66e7ba65bbf/pywin32_ctypes-0.2.3-py3-none-any.whl", hash = "sha256:8a1513379d709975552d202d942d9837758905c8d01eb82b8bcc30918929e7b8", size = 30756, upload-time = "2024-08-14T10:15:33.187Z" }, +] + +[[package]] +name = "pyyaml" +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" }, + { url = "https://files.pythonhosted.org/packages/51/16/6af8d6a6b210c8e54f1406a6b9481febf9c64a3109c541567e35a49aa2e7/PyYAML-6.0.2-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:5ac9328ec4831237bec75defaf839f7d4564be1e6b25ac710bd1a96321cc8317", size = 764167, upload-time = "2024-08-06T20:32:08.338Z" }, + { url = "https://files.pythonhosted.org/packages/75/e4/2c27590dfc9992f73aabbeb9241ae20220bd9452df27483b6e56d3975cc5/PyYAML-6.0.2-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3ad2a3decf9aaba3d29c8f537ac4b243e36bef957511b4766cb0057d32b0be85", size = 762952, upload-time = "2024-08-06T20:32:14.124Z" }, + { url = "https://files.pythonhosted.org/packages/9b/97/ecc1abf4a823f5ac61941a9c00fe501b02ac3ab0e373c3857f7d4b83e2b6/PyYAML-6.0.2-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:ff3824dc5261f50c9b0dfb3be22b4567a6f938ccce4587b38952d85fd9e9afe4", size = 735301, upload-time = "2024-08-06T20:32:16.17Z" }, + { url = "https://files.pythonhosted.org/packages/45/73/0f49dacd6e82c9430e46f4a027baa4ca205e8b0a9dce1397f44edc23559d/PyYAML-6.0.2-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:797b4f722ffa07cc8d62053e4cff1486fa6dc094105d13fea7b1de7d8bf71c9e", size = 756638, upload-time = "2024-08-06T20:32:18.555Z" }, + { url = "https://files.pythonhosted.org/packages/22/5f/956f0f9fc65223a58fbc14459bf34b4cc48dec52e00535c79b8db361aabd/PyYAML-6.0.2-cp311-cp311-win32.whl", hash = "sha256:11d8f3dd2b9c1207dcaf2ee0bbbfd5991f571186ec9cc78427ba5bd32afae4b5", size = 143850, upload-time = "2024-08-06T20:32:19.889Z" }, + { url = "https://files.pythonhosted.org/packages/ed/23/8da0bbe2ab9dcdd11f4f4557ccaf95c10b9811b13ecced089d43ce59c3c8/PyYAML-6.0.2-cp311-cp311-win_amd64.whl", hash = "sha256:e10ce637b18caea04431ce14fabcf5c64a1c61ec9c56b071a4b7ca131ca52d44", size = 161980, upload-time = "2024-08-06T20:32:21.273Z" }, + { url = "https://files.pythonhosted.org/packages/86/0c/c581167fc46d6d6d7ddcfb8c843a4de25bdd27e4466938109ca68492292c/PyYAML-6.0.2-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:c70c95198c015b85feafc136515252a261a84561b7b1d51e3384e0655ddf25ab", size = 183873, upload-time = "2024-08-06T20:32:25.131Z" }, + { url = "https://files.pythonhosted.org/packages/a8/0c/38374f5bb272c051e2a69281d71cba6fdb983413e6758b84482905e29a5d/PyYAML-6.0.2-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:ce826d6ef20b1bc864f0a68340c8b3287705cae2f8b4b1d932177dcc76721725", size = 173302, upload-time = "2024-08-06T20:32:26.511Z" }, + { url = "https://files.pythonhosted.org/packages/c3/93/9916574aa8c00aa06bbac729972eb1071d002b8e158bd0e83a3b9a20a1f7/PyYAML-6.0.2-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1f71ea527786de97d1a0cc0eacd1defc0985dcf6b3f17bb77dcfc8c34bec4dc5", size = 739154, upload-time = "2024-08-06T20:32:28.363Z" }, + { url = "https://files.pythonhosted.org/packages/95/0f/b8938f1cbd09739c6da569d172531567dbcc9789e0029aa070856f123984/PyYAML-6.0.2-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:9b22676e8097e9e22e36d6b7bda33190d0d400f345f23d4065d48f4ca7ae0425", size = 766223, upload-time = "2024-08-06T20:32:30.058Z" }, + { url = "https://files.pythonhosted.org/packages/b9/2b/614b4752f2e127db5cc206abc23a8c19678e92b23c3db30fc86ab731d3bd/PyYAML-6.0.2-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:80bab7bfc629882493af4aa31a4cfa43a4c57c83813253626916b8c7ada83476", size = 767542, upload-time = "2024-08-06T20:32:31.881Z" }, + { url = "https://files.pythonhosted.org/packages/d4/00/dd137d5bcc7efea1836d6264f049359861cf548469d18da90cd8216cf05f/PyYAML-6.0.2-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:0833f8694549e586547b576dcfaba4a6b55b9e96098b36cdc7ebefe667dfed48", size = 731164, upload-time = "2024-08-06T20:32:37.083Z" }, + { url = "https://files.pythonhosted.org/packages/c9/1f/4f998c900485e5c0ef43838363ba4a9723ac0ad73a9dc42068b12aaba4e4/PyYAML-6.0.2-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:8b9c7197f7cb2738065c481a0461e50ad02f18c78cd75775628afb4d7137fb3b", size = 756611, upload-time = "2024-08-06T20:32:38.898Z" }, + { url = "https://files.pythonhosted.org/packages/df/d1/f5a275fdb252768b7a11ec63585bc38d0e87c9e05668a139fea92b80634c/PyYAML-6.0.2-cp312-cp312-win32.whl", hash = "sha256:ef6107725bd54b262d6dedcc2af448a266975032bc85ef0172c5f059da6325b4", size = 140591, upload-time = "2024-08-06T20:32:40.241Z" }, + { url = "https://files.pythonhosted.org/packages/0c/e8/4f648c598b17c3d06e8753d7d13d57542b30d56e6c2dedf9c331ae56312e/PyYAML-6.0.2-cp312-cp312-win_amd64.whl", hash = "sha256:7e7401d0de89a9a855c839bc697c079a4af81cf878373abd7dc625847d25cbd8", size = 156338, upload-time = "2024-08-06T20:32:41.93Z" }, + { url = "https://files.pythonhosted.org/packages/ef/e3/3af305b830494fa85d95f6d95ef7fa73f2ee1cc8ef5b495c7c3269fb835f/PyYAML-6.0.2-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:efdca5630322a10774e8e98e1af481aad470dd62c3170801852d752aa7a783ba", size = 181309, upload-time = "2024-08-06T20:32:43.4Z" }, + { url = "https://files.pythonhosted.org/packages/45/9f/3b1c20a0b7a3200524eb0076cc027a970d320bd3a6592873c85c92a08731/PyYAML-6.0.2-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:50187695423ffe49e2deacb8cd10510bc361faac997de9efef88badc3bb9e2d1", size = 171679, upload-time = "2024-08-06T20:32:44.801Z" }, + { url = "https://files.pythonhosted.org/packages/7c/9a/337322f27005c33bcb656c655fa78325b730324c78620e8328ae28b64d0c/PyYAML-6.0.2-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0ffe8360bab4910ef1b9e87fb812d8bc0a308b0d0eef8c8f44e0254ab3b07133", size = 733428, upload-time = "2024-08-06T20:32:46.432Z" }, + { url = "https://files.pythonhosted.org/packages/a3/69/864fbe19e6c18ea3cc196cbe5d392175b4cf3d5d0ac1403ec3f2d237ebb5/PyYAML-6.0.2-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:17e311b6c678207928d649faa7cb0d7b4c26a0ba73d41e99c4fff6b6c3276484", size = 763361, upload-time = "2024-08-06T20:32:51.188Z" }, + { url = "https://files.pythonhosted.org/packages/04/24/b7721e4845c2f162d26f50521b825fb061bc0a5afcf9a386840f23ea19fa/PyYAML-6.0.2-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:70b189594dbe54f75ab3a1acec5f1e3faa7e8cf2f1e08d9b561cb41b845f69d5", size = 759523, upload-time = "2024-08-06T20:32:53.019Z" }, + { url = "https://files.pythonhosted.org/packages/2b/b2/e3234f59ba06559c6ff63c4e10baea10e5e7df868092bf9ab40e5b9c56b6/PyYAML-6.0.2-cp313-cp313-musllinux_1_1_aarch64.whl", hash = "sha256:41e4e3953a79407c794916fa277a82531dd93aad34e29c2a514c2c0c5fe971cc", size = 726660, upload-time = "2024-08-06T20:32:54.708Z" }, + { url = "https://files.pythonhosted.org/packages/fe/0f/25911a9f080464c59fab9027482f822b86bf0608957a5fcc6eaac85aa515/PyYAML-6.0.2-cp313-cp313-musllinux_1_1_x86_64.whl", hash = "sha256:68ccc6023a3400877818152ad9a1033e3db8625d899c72eacb5a668902e4d652", size = 751597, upload-time = "2024-08-06T20:32:56.985Z" }, + { url = "https://files.pythonhosted.org/packages/14/0d/e2c3b43bbce3cf6bd97c840b46088a3031085179e596d4929729d8d68270/PyYAML-6.0.2-cp313-cp313-win32.whl", hash = "sha256:bc2fa7c6b47d6bc618dd7fb02ef6fdedb1090ec036abab80d4681424b84c1183", size = 140527, upload-time = "2024-08-06T20:33:03.001Z" }, + { url = "https://files.pythonhosted.org/packages/fa/de/02b54f42487e3d3c6efb3f89428677074ca7bf43aae402517bc7cca949f3/PyYAML-6.0.2-cp313-cp313-win_amd64.whl", hash = "sha256:8388ee1976c416731879ac16da0aff3f63b286ffdd57cdeb95f3f2e085687563", size = 156446, upload-time = "2024-08-06T20:33:04.33Z" }, +] + +[[package]] +name = "requests" +version = "2.32.4" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "certifi" }, + { name = "charset-normalizer" }, + { name = "idna" }, + { name = "urllib3" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/e1/0a/929373653770d8a0d7ea76c37de6e41f11eb07559b103b1c02cafb3f7cf8/requests-2.32.4.tar.gz", hash = "sha256:27d0316682c8a29834d3264820024b62a36942083d52caf2f14c0591336d3422", size = 135258, upload-time = "2025-06-09T16:43:07.34Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/7c/e4/56027c4a6b4ae70ca9de302488c5ca95ad4a39e190093d6c1a8ace08341b/requests-2.32.4-py3-none-any.whl", hash = "sha256:27babd3cda2a6d50b30443204ee89830707d396671944c998b5975b031ac2b2c", size = 64847, upload-time = "2025-06-09T16:43:05.728Z" }, +] + +[[package]] +name = "scipy" +version = "1.15.3" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "numpy", version = "2.2.6", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version < '3.11'" }, + { name = "numpy", version = "2.3.0", source = { registry = "https://pypi.org/simple" }, 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 = "secretstorage" +version = "3.3.3" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "cryptography" }, + { name = "jeepney" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/53/a4/f48c9d79cb507ed1373477dbceaba7401fd8a23af63b837fa61f1dcd3691/SecretStorage-3.3.3.tar.gz", hash = "sha256:2403533ef369eca6d2ba81718576c5e0f564d5cca1b58f73a8b23e7d4eeebd77", size = 19739, upload-time = "2022-08-13T16:22:46.976Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/54/24/b4293291fa1dd830f353d2cb163295742fa87f179fcc8a20a306a81978b7/SecretStorage-3.3.3-py3-none-any.whl", hash = "sha256:f356e6628222568e3af06f2eba8df495efa13b3b63081dafd4f7d9a7b7bc9f99", size = 15221, upload-time = "2022-08-13T16:22:44.457Z" }, +] + +[[package]] +name = "six" +version = "1.17.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/94/e7/b2c673351809dca68a0e064b6af791aa332cf192da575fd474ed7d6f16a2/six-1.17.0.tar.gz", hash = "sha256:ff70335d468e7eb6ec65b95b99d3a2836546063f63acc5171de367e834932a81", size = 34031, upload-time = "2024-12-04T17:35:28.174Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/b7/ce/149a00dd41f10bc29e5921b496af8b574d8413afcd5e30dfa0ed46c2cc5e/six-1.17.0-py2.py3-none-any.whl", hash = "sha256:4721f391ed90541fddacab5acf947aa0d3dc7d27b2e1e8eda2be8970586c3274", size = 11050, upload-time = "2024-12-04T17:35:26.475Z" }, +] + +[[package]] +name = "soupsieve" +version = "2.7" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/3f/f4/4a80cd6ef364b2e8b65b15816a843c0980f7a5a2b4dc701fc574952aa19f/soupsieve-2.7.tar.gz", hash = "sha256:ad282f9b6926286d2ead4750552c8a6142bc4c783fd66b0293547c8fe6ae126a", size = 103418, upload-time = "2025-04-20T18:50:08.518Z" } +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 = "typing-extensions" +version = "4.14.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/d1/bc/51647cd02527e87d05cb083ccc402f93e441606ff1f01739a62c8ad09ba5/typing_extensions-4.14.0.tar.gz", hash = "sha256:8676b788e32f02ab42d9e7c61324048ae4c6d844a399eebace3d4979d75ceef4", size = 107423, upload-time = "2025-06-02T14:52:11.399Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/69/e0/552843e0d356fbb5256d21449fa957fa4eff3bbc135a74a691ee70c7c5da/typing_extensions-4.14.0-py3-none-any.whl", hash = "sha256:a1514509136dd0b477638fc68d6a91497af5076466ad0fa6c338e44e359944af", size = 43839, upload-time = "2025-06-02T14:52:10.026Z" }, +] + +[[package]] +name = "urllib3" +version = "2.5.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/15/22/9ee70a2574a4f4599c47dd506532914ce044817c7752a79b6a51286319bc/urllib3-2.5.0.tar.gz", hash = "sha256:3fc47733c7e419d4bc3f6b3dc2b4f890bb743906a30d56ba4a5bfa4bbff92760", size = 393185, upload-time = "2025-06-18T14:07:41.644Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/a7/c2/fe1e52489ae3122415c51f387e221dd0773709bad6c6cdaa599e8a2c5185/urllib3-2.5.0-py3-none-any.whl", hash = "sha256:e6b01673c0fa6a13e374b50871808eb3bf7046c4b125b216f6bf1cc604cff0dc", size = 129795, upload-time = "2025-06-18T14:07:40.39Z" }, +] + +[[package]] +name = "virtualenv" +version = "20.31.2" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "distlib" }, + { name = "filelock" }, + { name = "platformdirs" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/56/2c/444f465fb2c65f40c3a104fd0c495184c4f2336d65baf398e3c75d72ea94/virtualenv-20.31.2.tar.gz", hash = "sha256:e10c0a9d02835e592521be48b332b6caee6887f332c111aa79a09b9e79efc2af", size = 6076316, upload-time = "2025-05-08T17:58:23.811Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/f3/40/b1c265d4b2b62b58576588510fc4d1fe60a86319c8de99fd8e9fec617d2c/virtualenv-20.31.2-py3-none-any.whl", hash = "sha256:36efd0d9650ee985f0cad72065001e66d49a6f24eb44d98980f630686243cf11", size = 6057982, upload-time = "2025-05-08T17:58:21.15Z" }, +] + +[[package]] +name = "wcwidth" +version = "0.2.13" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/6c/63/53559446a878410fc5a5974feb13d31d78d752eb18aeba59c7fef1af7598/wcwidth-0.2.13.tar.gz", hash = "sha256:72ea0c06399eb286d978fdedb6923a9eb47e1c486ce63e9b4e64fc18303972b5", size = 101301, upload-time = "2024-01-06T02:10:57.829Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/fd/84/fd2ba7aafacbad3c4201d395674fc6348826569da3c0937e75505ead3528/wcwidth-0.2.13-py2.py3-none-any.whl", hash = "sha256:3da69048e4540d84af32131829ff948f1e022c1c6bdb8d6102117aac784f6859", size = 34166, upload-time = "2024-01-06T02:10:55.763Z" }, +] + +[[package]] +name = "webencodings" +version = "0.5.1" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/0b/02/ae6ceac1baeda530866a85075641cec12989bd8d31af6d5ab4a3e8c92f47/webencodings-0.5.1.tar.gz", hash = "sha256:b36a1c245f2d304965eb4e0a82848379241dc04b865afcc4aab16748587e1923", size = 9721, upload-time = "2017-04-05T20:21:34.189Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/f4/24/2a3e3df732393fed8b3ebf2ec078f05546de641fe1b667ee316ec1dcf3b7/webencodings-0.5.1-py2.py3-none-any.whl", hash = "sha256:a0af1213f3c2226497a97e2b3aa01a7e4bee4f403f95be16fc9acd2947514a78", size = 11774, upload-time = "2017-04-05T20:21:32.581Z" }, +] + +[[package]] +name = "win32-setctime" +version = "1.2.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/b3/8f/705086c9d734d3b663af0e9bb3d4de6578d08f46b1b101c2442fd9aecaa2/win32_setctime-1.2.0.tar.gz", hash = "sha256:ae1fdf948f5640aae05c511ade119313fb6a30d7eabe25fef9764dca5873c4c0", size = 4867, upload-time = "2024-12-07T15:28:28.314Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/e1/07/c6fe3ad3e685340704d314d765b7912993bcb8dc198f0e7a89382d37974b/win32_setctime-1.2.0-py3-none-any.whl", hash = "sha256:95d644c4e708aba81dc3704a116d8cbc974d70b3bdb8be1d150e36be6e9d1390", size = 4083, upload-time = "2024-12-07T15:28:26.465Z" }, +] + +[[package]] +name = "zipp" +version = "3.23.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/e3/02/0f2892c661036d50ede074e376733dca2ae7c6eb617489437771209d4180/zipp-3.23.0.tar.gz", hash = "sha256:a07157588a12518c9d4034df3fbbee09c814741a33ff63c05fa29d26a2404166", size = 25547, upload-time = "2025-06-08T17:06:39.4Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/2e/54/647ade08bf0db230bfea292f893923872fd20be6ac6f53b2b936ba839d75/zipp-3.23.0-py3-none-any.whl", hash = "sha256:071652d6115ed432f5ce1d34c336c0adfd6a884660d1e9712a256d3d3bd4b14e", size = 10276, upload-time = "2025-06-08T17:06:38.034Z" }, +] From 903dc21241fa16e2bdb35a7cd46d0b0d8376d639 Mon Sep 17 00:00:00 2001 From: rjtanner Date: Mon, 14 Jul 2025 18:35:42 -0400 Subject: [PATCH 02/17] Update documentation --- .../Using_pySASv2-checkpoint.ipynb | 2 +- documentation/Using_pySASv2.ipynb | 2 +- param.py | 2 +- parser.py | 23 +++++++++- sastask.py | 43 ++++++------------- 5 files changed, 37 insertions(+), 35 deletions(-) diff --git a/documentation/.ipynb_checkpoints/Using_pySASv2-checkpoint.ipynb b/documentation/.ipynb_checkpoints/Using_pySASv2-checkpoint.ipynb index 16c6ac6..ee7e1b6 100644 --- a/documentation/.ipynb_checkpoints/Using_pySASv2-checkpoint.ipynb +++ b/documentation/.ipynb_checkpoints/Using_pySASv2-checkpoint.ipynb @@ -44,7 +44,7 @@ "source": [ "Key changes:\n", " - `ObsID` is the new `ODFobject`\n", - " - The `Wrapper` has been depricated and replaced by `MyTask`\n", + " - The `Wrapper` has been deprecated and replaced by `MyTask`\n", "\n", "To implement these changes make the following modifications to your code:\n", "\n", diff --git a/documentation/Using_pySASv2.ipynb b/documentation/Using_pySASv2.ipynb index 16c6ac6..ee7e1b6 100644 --- a/documentation/Using_pySASv2.ipynb +++ b/documentation/Using_pySASv2.ipynb @@ -44,7 +44,7 @@ "source": [ "Key changes:\n", " - `ObsID` is the new `ODFobject`\n", - " - The `Wrapper` has been depricated and replaced by `MyTask`\n", + " - The `Wrapper` has been deprecated and replaced by `MyTask`\n", "\n", "To implement these changes make the following modifications to your code:\n", "\n", diff --git a/param.py b/param.py index 9209182..1b57582 100644 --- a/param.py +++ b/param.py @@ -90,7 +90,7 @@ def __init__(self, taskname): def xmlParser(self): """ The first task of xmlParser is to get the whole XML file as an object - of type Document (iFor a list of all objects, look at the xml.dom documentation). + of type Document (For a list of all objects, look at the xml.dom documentation). Then, it produces a list of Element objects in the paramater file which are identified by the tag 'PARAM'. This is done by means of the Element method getElementsByTagName. diff --git a/parser.py b/parser.py index 5e9c63d..b52568a 100644 --- a/parser.py +++ b/parser.py @@ -87,7 +87,7 @@ def __init__(self, taskname, arglist): # This is the task parser constructor def taskparser(self): - # Define the parser. Not need to make it class wide. + # Define the parser. No need to make it class wide. parser = argparse.ArgumentParser( prog = self.taskname, description = 'Parses command parameters and options', @@ -203,6 +203,25 @@ def taskparser(self): # Depending on the options entered, performs actions def procopt(self): + """ + Method to execute options or parameters that require immediate action. + + There are two sets of otions/parameters that require immediate action: + + 1. Options that execute the command and exit. These are: + version(--version, -v), help(--help, -h), param(--param, -p), + dialog(--dialog, -d) and manpage(--manpage, -m). + + 2. Options that set environment variables and then continue running + the SAS task. These are: + -V/--verbosity (SAS_VERBOSITY), -c/--noclobber, + (SAS_CLOBBER), -a/--ccfpath (SAS_CCFPATH), + -i/--ccf (SAS_CCF), -o/--odf (SAS_ODF), -f/--ccffiles, + -w/--warning, -t/--trace. + + Returns 'Exit' which if True will send the exit command up the chain. + If False, then pySAS will continue to execute. + """ # Exit is set to False Exit = False @@ -286,7 +305,7 @@ def procopt(self): # Excluding warning, which I do not know how to handle yet, # the next five options are accumulative, if they are present they change # environment variables. - # They do not return control to caller. + # They do not return control to caller. # # sas_ccfpath if self.parsedargs.sas_ccfpath: diff --git a/sastask.py b/sastask.py index 10ffd72..3118551 100644 --- a/sastask.py +++ b/sastask.py @@ -17,19 +17,7 @@ # """sastask.py -Defines a template SASTask Python class -based on the ABC (Abstract Base Classes) module. - -All SAS Pyhton based tasks will derive from SASTask. -However, they will not instantiate it but instead a -subclass of it, MyTask. There could be other similar -to MyTask, but for the time being we simply define this one. - -The methods defined in SASTask (decorated with -the @abstractmethod decorator), must be redefined in MyTask. -Otherwise, the instantiation of MyTask will fail. -By particularizing the methods defined in SASTask -we ensure all SAS Python based tasks have unified methods. +All stand alone SAS tasks can be called by using MyTask. As any other SAS task, Python based tasks are used to perform specific data processing jobs. @@ -56,30 +44,25 @@ Some of these options modify shell environment variables, e.g. SAS_VERBOSITY is modified by the value given to --verbosity, etc. -Let be mytask a new Python based task. It will be an instance of MyTask +Let be mytask a new SAS task. It will be an instance of MyTask mytask = MyTask('mytask', args) where args is a list that includes all arguments we pass to mytask -in the command line. As we will see this is not the only way to -pass arguments to the task. +in the command line. -mytask mandatory files and directories will be created by pkgmaker, -a Python script responsible of creating any type of SAS task, including -also those based on C++, Fortran 90 and Perl. - -The specific Python code for mytask, and possibly othe auxiliary Python +The specific Python code for mytask, and possibly other auxiliary Python code which might be required by mytask to operate, will be placed all within the directory structure of mytask. A typical invocation of mytask could be of the form -mytask param0=value0 [param1=value1] ... [Options] +MyTask('mytask', ['param0=value0','param1=value1', ... [Options]).run() where param0, param1, etc, are any task parameters defined in a file named mytask.par, and [Options] are any of the generic options common to all SAS task. If a parameter, e.g. param0, is defined in -mytask.par as 'mandatory', it must be present in the command line. +mytask.par as 'mandatory', it must be present. Of course, the presence of some of the Options, will trigger specific immediate actions: e.g. the option -v or --version will immediately @@ -89,22 +72,21 @@ The only requirement is that Options with a value, e.g. -V 4, must be adjacent. -Methods defined by SASTask (identified so far): +Methods defined by MyTask (identified so far): 1. readparfile: Read and loads the task parameter file. -2. processargs : Parses arguments and acts accordingly. +2. processargs: Parses arguments and acts accordingly. -3. runtask: Executes the task with the proper arguments. +3. run: Executes the task with the proper arguments. -MyTask will actually implement these three methods. +4. printHelp: Prints information about the task, equivalent to + MyTask('mytask', ['-h']).run() The readparfile method used class paramXmlInfoReader from param.py module. The processargs methdos uses the class ParseArgs based on argparse. - -The runtask method uses class RunTask. """ # Standard library imports @@ -460,10 +442,11 @@ def runtask(self): class SASTask(MyTask): """ Class SASTask is a child of MyTask and has access to all - of the methods in SASTask. It's only purpose is to act as + of the methods in MyTask. It's only purpose is to act as a placeholder for legacy code. """ def __init__(self, taskname, inargs): + super().__init__(taskname,inargs) warn( """ The class SASTask has been depricated. Use MyTask instead. From 26d3a89ea085c3c4a3c5fe7197b8741bf826cc77 Mon Sep 17 00:00:00 2001 From: rjtanner Date: Tue, 15 Jul 2025 13:17:45 -0400 Subject: [PATCH 03/17] Simplify paramXmlInfoReader --- param.py | 12 +++++------- 1 file changed, 5 insertions(+), 7 deletions(-) diff --git a/param.py b/param.py index 1b57582..6316fbb 100644 --- a/param.py +++ b/param.py @@ -75,13 +75,11 @@ def __init__(self, taskname): self.taskname = taskname self.xmlFile = '' - sas_path = os.environ['SAS_PATH'].split(':') - for path in sas_path: - parfile = self.taskname + '.par' - files = glob.glob(os.path.join(path, 'config', parfile)) - if files: - self.xmlFile = files[0] - break + sas_dir = os.environ['SAS_DIR'] + parfile = self.taskname + '.par' + files = glob.glob(os.path.join(sas_dir, 'config', parfile)) + if files: + self.xmlFile = files[0] if self.xmlFile == '': raise Exception(f'Does not exist any file named {parfile}. Wrong syntax?') From aa665e74cfa200ed0a9a8fa1c1fa323c584733a6 Mon Sep 17 00:00:00 2001 From: rjtanner Date: Tue, 15 Jul 2025 14:48:04 -0400 Subject: [PATCH 04/17] Add logger to parser and param --- param.py | 18 +++++++++++++----- parser.py | 13 ++++++++++--- sastask.py | 31 ++++++++++++++++++++++++++----- 3 files changed, 49 insertions(+), 13 deletions(-) diff --git a/param.py b/param.py index 6316fbb..a8473b6 100644 --- a/param.py +++ b/param.py @@ -53,7 +53,7 @@ from beautifultable import BeautifulTable # Local application imports -from pysas.error import Error as Err +from pysas.logger import get_logger class paramXmlInfoReader: @@ -69,17 +69,27 @@ class paramXmlInfoReader: an argument list. """ - def __init__(self, taskname): + def __init__(self, taskname, logger = None): """taskname to be handled.""" self.taskname = taskname self.xmlFile = '' + if logger is None: + # By default will only output to terminal + self.logger = get_logger('paramXmlInfoReader') + else: + # Use logger that was passed in + self.logger = logger sas_dir = os.environ['SAS_DIR'] + self.logger.debug(f'SAS_DIR: {sas_dir}') parfile = self.taskname + '.par' + self.logger.debug(f'Parfile name: {parfile}') files = glob.glob(os.path.join(sas_dir, 'config', parfile)) + self.logger.debug(f'Parfile location: {files}') if files: self.xmlFile = files[0] + self.logger.debug(f'xmlFile: {self.xmlFile}') if self.xmlFile == '': raise Exception(f'Does not exist any file named {parfile}. Wrong syntax?') @@ -151,9 +161,7 @@ def xmlParser(self): try: doc = md.parse(self.xmlFile) except: - Err(client=self.taskname, - code='openFileError', - msg=f'ERROR opening par file {self.taskname}.par: {self.xmlFile}').error() + self.logger.error(f'ERROR opening par file {self.taskname}.par: {self.xmlFile}') sys.exit(1) # self.params diff --git a/parser.py b/parser.py index b52568a..fe50f13 100644 --- a/parser.py +++ b/parser.py @@ -54,12 +54,19 @@ # Local application imports from pysas.param import paramXmlInfoReader +from pysas.logger import get_logger from .configutils import sas_cfg class ParseArgs: - def __init__(self, taskname, arglist): + def __init__(self, taskname, arglist, logger = None): self.taskname = taskname self.arglist = arglist + if logger is None: + # By default will only output to terminal + self.logger = get_logger('ParseArgs') + else: + # Use logger that was passed in + self.logger = logger # Before any further processing check that SAS_PATH is defined sas_path = os.environ.get('SAS_PATH') @@ -276,12 +283,12 @@ def procopt(self): # Help: if self.parsedargs.help: print(usage) - pf = paramXmlInfoReader(self.taskname) + pf = paramXmlInfoReader(self.taskname, logger = self.logger) pf.xmlParser() pf.printHelp() Exit = True if self.parsedargs.param: - pf = paramXmlInfoReader(self.taskname) + pf = paramXmlInfoReader(self.taskname, logger = self.logger) pf.xmlParser() pf.printHelp() Exit = True diff --git a/sastask.py b/sastask.py index 3118551..f323c3d 100644 --- a/sastask.py +++ b/sastask.py @@ -86,7 +86,7 @@ The readparfile method used class paramXmlInfoReader from param.py module. -The processargs methdos uses the class ParseArgs based on argparse. +The processargs methods uses the class ParseArgs based on argparse. """ # Standard library imports @@ -150,7 +150,8 @@ def __init__(self, taskname, inargs, logfilename = None, tasklogdir = None, output_to_terminal = True, - output_to_file = False): + output_to_file = False, + logger = None): self.taskname = taskname self.inargs = inargs self.logfilename = logfilename @@ -158,10 +159,30 @@ def __init__(self, taskname, inargs, self.output_to_terminal = output_to_terminal self.output_to_file = output_to_file + # The logger object assigned here will only be used for log information + # generated by pySAS. Log information generated by SAS tasks will not + # be controled by this logger object. + # If a logger object was not passed in, then generate one + if logger is None: + if logfilename is None: + # If no logfilename is given, then only write out to terminal + self.logger = get_logger('MyTask', + toterminal = self.output_to_terminal) + else: + # If a logfilename was given then use that + self.logger = get_logger('MyTask', + toterminal = self.output_to_terminal, + tofile = self.output_to_file, + logfilename = self.logfilename, + tasklogdir = self.tasklogdir) + else: + # If a logger object was passed in, then use that. + self.logger = logger + # Check if inargs is a 'dict'. If it is then convert to list format. if isinstance(self.inargs, dict): # Get dict of default inputs for the task. - t = paramXmlInfoReader(self.taskname) + t = paramXmlInfoReader(self.taskname, logger = self.logger) t.xmlParser() defdict = t.defaultValues() defkeys = defdict.keys() @@ -198,7 +219,7 @@ def __repr__(self): return f'{self.__class__.__name__}({self.taskname}, {self.inargs})' def readparfile(self): - t = paramXmlInfoReader(self.taskname) + t = paramXmlInfoReader(self.taskname, logger = self.logger) t.xmlParser() self.allparams = t.allparams self.mandparams = t.mandpar @@ -209,7 +230,7 @@ def readparfile(self): self.rev_mandpar_string_dict = t.rev_mandpar_string_dict def processargs(self): - p = ParseArgs(self.taskname, self.inargs) + p = ParseArgs(self.taskname, self.inargs, logger = self.logger) p.taskparser() # tparams is a list with the left hands of param=value, if any self.tparams = p.tparams From c3404c9e88c4421213e489fa6941085d938efd5f Mon Sep 17 00:00:00 2001 From: rjtanner Date: Tue, 15 Jul 2025 16:05:31 -0400 Subject: [PATCH 05/17] Update ChangeLog --- ChangeLog | 4 ++++ param.py | 1 + 2 files changed, 5 insertions(+) diff --git a/ChangeLog b/ChangeLog index 14d12ad..aa3e35c 100644 --- a/ChangeLog +++ b/ChangeLog @@ -62,4 +62,8 @@ Version 2.0 - 2025-??-?? (RT) 2. ODF (Child class of ObsID) 3. PPS (Child class of ObsID) ++ parser.py : Update documentation, add logger to ParseArgs + ++ param.py : Update documentation, add logger to paramXmlInfoReader + diff --git a/param.py b/param.py index a8473b6..d726163 100644 --- a/param.py +++ b/param.py @@ -346,6 +346,7 @@ def el2nam(p, pels): pname = pels[p] return pname +# This needs to be rewritten def get_input_params(taskname,return_param_obj=False): """ Function to return dictionary of input parameters for a given From bb649a98d42762b12c680d31724ef1edd2c44c8e Mon Sep 17 00:00:00 2001 From: rjtanner Date: Tue, 15 Jul 2025 16:58:16 -0400 Subject: [PATCH 06/17] Convert inargs to dictionary --- ChangeLog | 3 +- parser.py | 47 ++++++++++++--------------- sastask.py | 93 +++++++++++++++++++++++------------------------------- 3 files changed, 61 insertions(+), 82 deletions(-) diff --git a/ChangeLog b/ChangeLog index aa3e35c..defdc00 100644 --- a/ChangeLog +++ b/ChangeLog @@ -62,7 +62,8 @@ Version 2.0 - 2025-??-?? (RT) 2. ODF (Child class of ObsID) 3. PPS (Child class of ObsID) -+ parser.py : Update documentation, add logger to ParseArgs ++ parser.py : Update documentation, add logger to ParseArgs, changed 'taskparser' to + 'optparser'. + param.py : Update documentation, add logger to paramXmlInfoReader diff --git a/parser.py b/parser.py index fe50f13..9586eec 100644 --- a/parser.py +++ b/parser.py @@ -26,7 +26,7 @@ Then it populates the pysaspkgs list with all packages below pysas. This is used to get the version of the package. -The instance method taskparser uses module argparse to define the +The instance method optparser uses module argparse to define the two types of arguments supported: options and parameters. Options can be classified into two categories: immediate action and execution modifiers. Options are accessed via the a single or a @@ -58,9 +58,13 @@ from .configutils import sas_cfg class ParseArgs: - def __init__(self, taskname, arglist, logger = None): + """ + For pySAS v2.0 it is now assumed that the input arguments are + passed in as a dictionary. + """ + def __init__(self, taskname, argdict, logger = None): self.taskname = taskname - self.arglist = arglist + self.argdict = argdict if logger is None: # By default will only output to terminal self.logger = get_logger('ParseArgs') @@ -92,7 +96,10 @@ def __init__(self, taskname, arglist, logger = None): self.version = subprocess.check_output(cmd, shell=True, text=True) # This is the task parser constructor - def taskparser(self): + def optparser(self): + """ + This parses the 'options' from the input. + """ # Define the parser. No need to make it class wide. parser = argparse.ArgumentParser( @@ -178,35 +185,21 @@ def taskparser(self): action='store_true', default=False) - # To give access to real SAS style params in the form param=value, - # we add a positional string argument, which can be repeated any - # number of times, but always contiguously. - # Notice that this is already achieved due to the initial processing - # made in self.arglist, where these strings have been grouped together - # at the end of self.arglist. We call this argument pvpairs. - - parser.add_argument('pvpairs', type=str, nargs='*') + # Apply parse_args method to parser with the options being passed in. + # Result is put into parsedargs. The parsedargs object is not a + # dictionary but can be shown as such with function vars(). - # Apply parse_args method to parser. Result is put into parsedargs. - # The parsedargs object is not a dictionary but can be shown as such - # with function vars(). - - self.parsedargs = parser.parse_args(self.arglist) + self.parsedargs = parser.parse_args(self.argdict['options']) #print(self.parsedargs) #print(f'vars(self.parsedargs) = \n{vars(self.parsedargs)}') #print(f'self.parsedargs.pvpairs = {self.parsedargs.pvpairs}') - # Put into list tparams only the real parameters entered in the command line + # Put into list tparams parameters entered in the command line # as pairs param=value - self.tparams = [] - pp = '' - for p in self.parsedargs.pvpairs: - a, b = p.split('=', 1) - self.tparams.append(a) - - #print(f'self.tparams = {self.tparams}') + params = list(self.argdict.keys()) + self.tparams = params.remove('options') # Depending on the options entered, performs actions def procopt(self): @@ -268,7 +261,7 @@ def procopt(self): # p.procopt() the return Exit determines wheter to return immediately or # not. If Exit is set to True, the method will return immediately. # - # Some options entered in self.arglist will launch special SAS tasks + # Some options entered in self.argdict will launch special SAS tasks # designed only to provide specific result. These are: # # -d/--dialog => sasdialog to launch task GUI @@ -345,7 +338,7 @@ def procopt(self): return Exit def __repr__(self): - return f'{self.__class__.__name__}({self.taskname} - {self.arglist})' + return f'{self.__class__.__name__}({self.taskname} - {self.argdict})' def runext(self, runcmd): self.runcmd = runcmd diff --git a/sastask.py b/sastask.py index f323c3d..eeaba63 100644 --- a/sastask.py +++ b/sastask.py @@ -129,6 +129,9 @@ class MyTask: a log file. + For pySAS v2.0 the inargs has switched to fundamentally being a dictionary. + If a list is passed in it will be converted into a dictionary. + In the class initialization, the task name and the input args to run it are processed. Task parameters as identified by the '=' sign are @@ -179,41 +182,25 @@ def __init__(self, taskname, inargs, # If a logger object was passed in, then use that. self.logger = logger - # Check if inargs is a 'dict'. If it is then convert to list format. + # Check if inargs is a 'dict'. if isinstance(self.inargs, dict): - # Get dict of default inputs for the task. - t = paramXmlInfoReader(self.taskname, logger = self.logger) - t.xmlParser() - defdict = t.defaultValues() - defkeys = defdict.keys() - inkeys = self.inargs.keys() - outparams = [] - - # Loop over all keys in the inargs dict and add values in - # the outdict, but only if different from default values. - # Build outparams. - for key in list(inkeys): - if key == 'options': - # Only if 'options' is not empty. - if self.inargs[key] != '': - outparams.append(self.inargs[key]) + # Insert empty string for options if not present + if not 'options' in self.inargs.keys(): + self.inargs['options'] = '' + + # If inargs is a list, pick off all the options, then put + # all other arguments into key-value pairs in the dictionary. + if isinstance(self.inargs, list): + argsdic = {} + options = [] + for a in self.inargs: + if '=' in a: + k, v = a.split('=', 1) + argsdic[k] = v else: - # Safety check to see if a number was passed in. - if isinstance(self.inargs[key], numbers.Number): - self.inargs[key] = str(self.inargs[key]) - outparams.append(key+'='+self.inargs[key]) - self.inargs = outparams - - # Reorder self.inargs to group together all options and - # all args of type param=value, in that order. - sasparams = [] - options = [] - for a in self.inargs: - if '=' in a.split('=',1): - sasparams.append(a) - else: - options.append(a) - self.inargs = [*options, *sasparams] + options.append(a) + argsdic['options'] = " ".join(options) + self.inargs = argsdic def __repr__(self): return f'{self.__class__.__name__}({self.taskname}, {self.inargs})' @@ -231,9 +218,7 @@ def readparfile(self): def processargs(self): p = ParseArgs(self.taskname, self.inargs, logger = self.logger) - p.taskparser() - # tparams is a list with the left hands of param=value, if any - self.tparams = p.tparams + p.optparser() # Execute options which require immediate action # Options which are for environment (which are cumulative) @@ -241,23 +226,27 @@ def processargs(self): self.Exit = p.procopt() if self.Exit: return self.Exit + + # Remove the options from inargs + self.argsdic = self.inargs.pop('options', None) + # 1st check: Whether or not parameters in inargs are defined in the parameter file - for p in self.tparams: + for p in self.argsdic.keys(): if p.strip() not in self.allparams.keys(): raise Exception(f'Parameter {p} is not defined in the parameter file') # 2nd check: Whether we have mandatory parameters and subparameters for k, v in self.rev_mandpar_dict.items(): - if k.strip() in v and k.strip() not in self.tparams: + if k.strip() in v and k.strip() not in self.argsdic.keys(): raise Exception(f'Missing, at least, mandatory parameter {k}') if k not in v: - for p in self.tparams: + for p in self.argsdic.keys(): if p in v: implicit = 'yes' for c in v: - if c not in self.tparams: + if c not in self.argsdic.keys(): implicit = 'no' raise Exception(f'Besides {p}, mandatory subparameter {c} must also be present') if implicit == 'yes': @@ -270,11 +259,11 @@ def processargs(self): elif self.allparams[k]['type'] == 'bool' and defval == 'yes': alt = 'no' newinarg = k + '=' + alt - self.inargs.append(newinarg) - if k in self.tparams: + self.argsdic[k] = alt + if k in self.argsdic.keys(): print(f'Warning: No need to include {k}. Assumed {newinarg}') break - elif p in v and k not in self.tparams: + elif p in v and k not in self.argsdic.keys(): raise Exception(f'Mandatory sub-parameter {p} requires {k} be present') # If any subparameters of a parent parameter are set in the command @@ -287,7 +276,7 @@ def processargs(self): # parameters having subparameters. # The final effect of this will be visible below when merging # the parsdic (the dictionary with the default values for - # all the parameters) and the argsdic to pass all task + # all the parameters) and the inargs to pass all task # parameters for execution. # Now compute a dictionary for all implicit parameters. @@ -314,11 +303,7 @@ def processargs(self): # argsdic is a dictionary with the pairs param, value # as entered from the command line from 'param=value' - argsdic = {} - for a in self.inargs: - if '=' in a: - k, v = a.split('=', 1) - argsdic[k] = v + argsdic = self.inargs # Load defaults with all parameters default values. # Use dictionary method 'setdefault' to set the value for a given key; @@ -329,10 +314,10 @@ def processargs(self): for a in self.allparams.values(): defaults[a['id']] = a.setdefault('default', '') - # 3rd Check: Whether any subparameter is set in argsdic or not. + # 3rd Check: Whether any subparameter is set in self.argsdic or not. # We assume the parent is boolean ('yes'/'no'). - for a in argsdic.keys(): + for a in self.argsdic.keys(): for k, v in implicitparams.items(): if a in v: #print(f'parent = {k}') @@ -343,12 +328,12 @@ def processargs(self): #print(k, a, defaults[k]) break - # Merge argsdic onto parsdic. Those values set in command line, - # from argsdic, will overwrite the defaults obtained from the par file, + # Merge self.argsdic onto parsdic. Those values set in command line, + # from self.argsdic, will overwrite the defaults obtained from the par file, # from parsdic. The resulting dictionary, self.iparsdic, is what we will # pass to method runtask. - self.iparsdic = {**defaults, **argsdic} + self.iparsdic = {**defaults, **self.argsdic} def printHelp(self): self.paramXmlInfo.printHelp() From 6106ce50c3f230271b51140a10254855e9779f42 Mon Sep 17 00:00:00 2001 From: rjtanner Date: Wed, 16 Jul 2025 12:49:54 -0400 Subject: [PATCH 07/17] Update documentation and how inputs are handled --- .../Basics_of_pySAS-checkpoint.ipynb | 89 +++++++----- documentation/Basics_of_pySAS.ipynb | 89 +++++++----- documentation/Using_pySASv2.ipynb | 133 +++++++++--------- obsid/obsid.py | 26 ++-- sastask.py | 25 +++- 5 files changed, 215 insertions(+), 147 deletions(-) diff --git a/documentation/.ipynb_checkpoints/Basics_of_pySAS-checkpoint.ipynb b/documentation/.ipynb_checkpoints/Basics_of_pySAS-checkpoint.ipynb index fd67804..3f7ad42 100644 --- a/documentation/.ipynb_checkpoints/Basics_of_pySAS-checkpoint.ipynb +++ b/documentation/.ipynb_checkpoints/Basics_of_pySAS-checkpoint.ipynb @@ -69,27 +69,42 @@ "```python\n", "from pysas.sastask import MyTask\n", "```\n", - "`MyTask` takes two inputs, the first is the name of the SAS task as a string. The second is a list with the input arguments for the SAS task. Each input argument must be a string. If there are no input arguments then the list will be empty:\n", + "`MyTask` takes two inputs, the first is the name of the SAS task as a string. The second is a dictionary with the input arguments for the SAS task. If there are no input arguments then the dictionary will be empty:\n", "```python\n", - "MyTask('sasver', []).run()\n", + "MyTask('sasversion', {}).run()\n", "```\n", "\n", - "Each input argument must be a separate string in the list:\n", + "Each input argument will take the form of a 'key' (parameter name) and 'value' (parameter value) pair. Each parameter value should be a single string.\n", "```python\n", - "inargs = ['table=event_list.fits', \n", - " 'withfilteredset=yes', \n", - " \"expression='(PATTERN <= 12)&&(PI in [200:4000])&&#XMMEA_EM'\", \n", - " 'filteredset=filtered_event_list.fits', \n", - " 'filtertype=expression', \n", - " 'keepfilteroutput=yes', \n", - " 'updateexposure=yes', \n", - " 'filterexposure=yes']\n", + "inargs = {'table' : 'event_list.fits',\n", + " 'withfilteredset' : 'yes',\n", + " \"expression\" : \"'(PATTERN <= 12)&&(PI in [200:4000])&&#XMMEA_EM'\",\n", + " 'filteredset' : 'filtered_event_list.fits',\n", + " 'filtertype' : 'expression', \n", + " 'keepfilteroutput': 'yes',\n", + " 'updateexposure' : 'yes',\n", + " 'filterexposure' : 'yes'}\n", "\n", "MyTask('evselect', inargs).run()\n", "```\n", "
\n", - " Note: Some inputs require single quotes to be preserved in the string. This can be done using double quotes to form the string. i.e. \"expression='(PATTERN <= 12)&&(PI in [200:4000])&&#XMMEA_EM'\"\n", - "
" + " Note: Some inputs require single quotes to be preserved in the string. This can be done using double quotes to form the string. i.e. \"'(PATTERN <= 12)&&(PI in [200:4000])&&#XMMEA_EM'\"\n", + "\n", + "\n", + "If you need to pass in command line options to a SAS task, add it to the dictionary with they key '`options`'. For example,\n", + "```python\n", + "inargs = {'options' : '--verbosity 6 --noclobber'\n", + " 'table' : 'event_list.fits',\n", + " 'withfilteredset' : 'yes',\n", + " \"expression\" : \"'(PATTERN <= 12)&&(PI in [200:4000])&&#XMMEA_EM'\",\n", + " 'filteredset' : 'filtered_event_list.fits',\n", + " 'filtertype' : 'expression', \n", + " 'keepfilteroutput': 'yes',\n", + " 'updateexposure' : 'yes',\n", + " 'filterexposure' : 'yes'}\n", + "\n", + "MyTask('evselect', inargs).run()\n", + "```" ] }, { @@ -270,25 +285,10 @@ "id": "9d88b1a4-026a-45d4-b707-f026959c6e02", "metadata": {}, "source": [ - "As noted above, for all SAS tasks, input arguments should be in a list, with each input argument a separate string. \n", + "As noted above, for all SAS tasks, input arguments should be in dictionary, with each parameter value a single string. \n", "\n", "For example,\n", "```python\n", - "inargs = ['table=event_list.fits', \n", - " 'withfilteredset=yes', \n", - " \"expression='(PATTERN <= 12)&&(PI in [200:4000])&&#XMMEA_EM'\", \n", - " 'filteredset=filtered_event_list.fits', \n", - " 'filtertype=expression', \n", - " 'keepfilteroutput=yes', \n", - " 'updateexposure=yes', \n", - " 'filterexposure=yes']\n", - "\n", - "MyTask('evselect', inargs).run()\n", - "```\n", - "\n", - "The development version of pySAS allows inputs to be passed in as a Python dictionary. For example, the same list of input arguments shown above could be written like this:\n", - "\n", - "```python\n", "inargs = {'table' : 'event_list.fits', \n", " 'withfilteredset' : 'yes', \n", " 'expression' : \"'(PATTERN <= 12)&&(PI in [200:4000])&&#XMMEA_EM'\", \n", @@ -300,7 +300,6 @@ "\n", "MyTask('evselect', inargs).run()\n", "```\n", - "\n", "or it could even be written like this:\n", "\n", "```python\n", @@ -324,9 +323,21 @@ "MyTask('evselect', inargs).run()\n", "```\n", "\n", - "The reason why this capability was added was for experimental reasons and to allow greater flexibility in interacting with pySAS.\n", + "For versions of pySAS before v2.0, the input arguments were passed in as a list. And in pySAS v2.0 you can still pass in the input arguments as a list.\n", + "```python\n", + "inargs = ['table=event_list.fits', \n", + " 'withfilteredset=yes', \n", + " \"expression='(PATTERN <= 12)&&(PI in [200:4000])&&#XMMEA_EM'\", \n", + " 'filteredset=filtered_event_list.fits', \n", + " 'filtertype=expression', \n", + " 'keepfilteroutput=yes', \n", + " 'updateexposure=yes', \n", + " 'filterexposure=yes']\n", "\n", - "While the values for all input arguments should be in string format, the development version of pySAS will accept numbers, as shown below. These numbers will be converted into strings automatically.\n", + "MyTask('evselect', inargs).run()\n", + "```\n", + "\n", + "While the values for all input arguments should be in string format, pySAS v2.0 will accept numbers, as shown below. These numbers will be converted into strings automatically.\n", "\n", "```python\n", "inargs = {}\n", @@ -340,6 +351,20 @@ "MyTask('rgsrmfgen', inargs).run()\n", "```\n", "\n", + "Also in pySAS v2.0 'yes/no' parameters can be passed in as a boolean:\n", + "```python\n", + "inargs = {'table' : 'event_list.fits', \n", + " 'withfilteredset' : True, \n", + " 'expression' : \"'(PATTERN <= 12)&&(PI in [200:4000])&&#XMMEA_EM'\", \n", + " 'filteredset' : 'filtered_event_list.fits', \n", + " 'filtertype' : 'expression', \n", + " 'keepfilteroutput' : True, \n", + " 'updateexposure' : True, \n", + " 'filterexposure' : True}\n", + "\n", + "MyTask('evselect', inargs).run()\n", + "```\n", + "\n", "The user can get all the default parameters for any SAS task by using:\n", "```python\n", "task_name = 'insert_task_name'\n", diff --git a/documentation/Basics_of_pySAS.ipynb b/documentation/Basics_of_pySAS.ipynb index fd67804..3f7ad42 100644 --- a/documentation/Basics_of_pySAS.ipynb +++ b/documentation/Basics_of_pySAS.ipynb @@ -69,27 +69,42 @@ "```python\n", "from pysas.sastask import MyTask\n", "```\n", - "`MyTask` takes two inputs, the first is the name of the SAS task as a string. The second is a list with the input arguments for the SAS task. Each input argument must be a string. If there are no input arguments then the list will be empty:\n", + "`MyTask` takes two inputs, the first is the name of the SAS task as a string. The second is a dictionary with the input arguments for the SAS task. If there are no input arguments then the dictionary will be empty:\n", "```python\n", - "MyTask('sasver', []).run()\n", + "MyTask('sasversion', {}).run()\n", "```\n", "\n", - "Each input argument must be a separate string in the list:\n", + "Each input argument will take the form of a 'key' (parameter name) and 'value' (parameter value) pair. Each parameter value should be a single string.\n", "```python\n", - "inargs = ['table=event_list.fits', \n", - " 'withfilteredset=yes', \n", - " \"expression='(PATTERN <= 12)&&(PI in [200:4000])&&#XMMEA_EM'\", \n", - " 'filteredset=filtered_event_list.fits', \n", - " 'filtertype=expression', \n", - " 'keepfilteroutput=yes', \n", - " 'updateexposure=yes', \n", - " 'filterexposure=yes']\n", + "inargs = {'table' : 'event_list.fits',\n", + " 'withfilteredset' : 'yes',\n", + " \"expression\" : \"'(PATTERN <= 12)&&(PI in [200:4000])&&#XMMEA_EM'\",\n", + " 'filteredset' : 'filtered_event_list.fits',\n", + " 'filtertype' : 'expression', \n", + " 'keepfilteroutput': 'yes',\n", + " 'updateexposure' : 'yes',\n", + " 'filterexposure' : 'yes'}\n", "\n", "MyTask('evselect', inargs).run()\n", "```\n", "
\n", - " Note: Some inputs require single quotes to be preserved in the string. This can be done using double quotes to form the string. i.e. \"expression='(PATTERN <= 12)&&(PI in [200:4000])&&#XMMEA_EM'\"\n", - "
" + " Note: Some inputs require single quotes to be preserved in the string. This can be done using double quotes to form the string. i.e. \"'(PATTERN <= 12)&&(PI in [200:4000])&&#XMMEA_EM'\"\n", + "\n", + "\n", + "If you need to pass in command line options to a SAS task, add it to the dictionary with they key '`options`'. For example,\n", + "```python\n", + "inargs = {'options' : '--verbosity 6 --noclobber'\n", + " 'table' : 'event_list.fits',\n", + " 'withfilteredset' : 'yes',\n", + " \"expression\" : \"'(PATTERN <= 12)&&(PI in [200:4000])&&#XMMEA_EM'\",\n", + " 'filteredset' : 'filtered_event_list.fits',\n", + " 'filtertype' : 'expression', \n", + " 'keepfilteroutput': 'yes',\n", + " 'updateexposure' : 'yes',\n", + " 'filterexposure' : 'yes'}\n", + "\n", + "MyTask('evselect', inargs).run()\n", + "```" ] }, { @@ -270,25 +285,10 @@ "id": "9d88b1a4-026a-45d4-b707-f026959c6e02", "metadata": {}, "source": [ - "As noted above, for all SAS tasks, input arguments should be in a list, with each input argument a separate string. \n", + "As noted above, for all SAS tasks, input arguments should be in dictionary, with each parameter value a single string. \n", "\n", "For example,\n", "```python\n", - "inargs = ['table=event_list.fits', \n", - " 'withfilteredset=yes', \n", - " \"expression='(PATTERN <= 12)&&(PI in [200:4000])&&#XMMEA_EM'\", \n", - " 'filteredset=filtered_event_list.fits', \n", - " 'filtertype=expression', \n", - " 'keepfilteroutput=yes', \n", - " 'updateexposure=yes', \n", - " 'filterexposure=yes']\n", - "\n", - "MyTask('evselect', inargs).run()\n", - "```\n", - "\n", - "The development version of pySAS allows inputs to be passed in as a Python dictionary. For example, the same list of input arguments shown above could be written like this:\n", - "\n", - "```python\n", "inargs = {'table' : 'event_list.fits', \n", " 'withfilteredset' : 'yes', \n", " 'expression' : \"'(PATTERN <= 12)&&(PI in [200:4000])&&#XMMEA_EM'\", \n", @@ -300,7 +300,6 @@ "\n", "MyTask('evselect', inargs).run()\n", "```\n", - "\n", "or it could even be written like this:\n", "\n", "```python\n", @@ -324,9 +323,21 @@ "MyTask('evselect', inargs).run()\n", "```\n", "\n", - "The reason why this capability was added was for experimental reasons and to allow greater flexibility in interacting with pySAS.\n", + "For versions of pySAS before v2.0, the input arguments were passed in as a list. And in pySAS v2.0 you can still pass in the input arguments as a list.\n", + "```python\n", + "inargs = ['table=event_list.fits', \n", + " 'withfilteredset=yes', \n", + " \"expression='(PATTERN <= 12)&&(PI in [200:4000])&&#XMMEA_EM'\", \n", + " 'filteredset=filtered_event_list.fits', \n", + " 'filtertype=expression', \n", + " 'keepfilteroutput=yes', \n", + " 'updateexposure=yes', \n", + " 'filterexposure=yes']\n", "\n", - "While the values for all input arguments should be in string format, the development version of pySAS will accept numbers, as shown below. These numbers will be converted into strings automatically.\n", + "MyTask('evselect', inargs).run()\n", + "```\n", + "\n", + "While the values for all input arguments should be in string format, pySAS v2.0 will accept numbers, as shown below. These numbers will be converted into strings automatically.\n", "\n", "```python\n", "inargs = {}\n", @@ -340,6 +351,20 @@ "MyTask('rgsrmfgen', inargs).run()\n", "```\n", "\n", + "Also in pySAS v2.0 'yes/no' parameters can be passed in as a boolean:\n", + "```python\n", + "inargs = {'table' : 'event_list.fits', \n", + " 'withfilteredset' : True, \n", + " 'expression' : \"'(PATTERN <= 12)&&(PI in [200:4000])&&#XMMEA_EM'\", \n", + " 'filteredset' : 'filtered_event_list.fits', \n", + " 'filtertype' : 'expression', \n", + " 'keepfilteroutput' : True, \n", + " 'updateexposure' : True, \n", + " 'filterexposure' : True}\n", + "\n", + "MyTask('evselect', inargs).run()\n", + "```\n", + "\n", "The user can get all the default parameters for any SAS task by using:\n", "```python\n", "task_name = 'insert_task_name'\n", diff --git a/documentation/Using_pySASv2.ipynb b/documentation/Using_pySASv2.ipynb index ee7e1b6..0d5d185 100644 --- a/documentation/Using_pySASv2.ipynb +++ b/documentation/Using_pySASv2.ipynb @@ -45,6 +45,7 @@ "Key changes:\n", " - `ObsID` is the new `ODFobject`\n", " - The `Wrapper` has been deprecated and replaced by `MyTask`\n", + " - Input arguments can be passed in as either a dictionary or a list\n", "\n", "To implement these changes make the following modifications to your code:\n", "\n", @@ -211,8 +212,8 @@ "calibrate_odf(obs_dir = None,\n", " sas_ccf = None,\n", " sas_odf = None,\n", - " cifbuild_opts = [],\n", - " odfingest_opts = [],\n", + " cifbuild_opts = {},\n", + " odfingest_opts = {},\n", " recalibrate = False)\n", "\n", "get_active_instruments()\n", @@ -283,11 +284,11 @@ "id": "15b25239-d5ef-48a6-bb26-6fa4296ed2de", "metadata": { "execution": { - "iopub.execute_input": "2025-07-11T18:13:04.504348Z", - "iopub.status.busy": "2025-07-11T18:13:04.504233Z", - "iopub.status.idle": "2025-07-11T18:13:04.903347Z", - "shell.execute_reply": "2025-07-11T18:13:04.902834Z", - "shell.execute_reply.started": "2025-07-11T18:13:04.504336Z" + "iopub.execute_input": "2025-07-16T16:48:08.985884Z", + "iopub.status.busy": "2025-07-16T16:48:08.985775Z", + "iopub.status.idle": "2025-07-16T16:48:09.404326Z", + "shell.execute_reply": "2025-07-16T16:48:09.403577Z", + "shell.execute_reply.started": "2025-07-16T16:48:08.985872Z" } }, "outputs": [], @@ -309,11 +310,11 @@ "id": "7bbe67c0-6e5a-43ad-a0c2-ead5dd806e38", "metadata": { "execution": { - "iopub.execute_input": "2025-07-11T18:13:04.903993Z", - "iopub.status.busy": "2025-07-11T18:13:04.903868Z", - "iopub.status.idle": "2025-07-11T18:13:04.923423Z", - "shell.execute_reply": "2025-07-11T18:13:04.922811Z", - "shell.execute_reply.started": "2025-07-11T18:13:04.903982Z" + "iopub.execute_input": "2025-07-16T16:48:09.404973Z", + "iopub.status.busy": "2025-07-16T16:48:09.404840Z", + "iopub.status.idle": "2025-07-16T16:48:09.426058Z", + "shell.execute_reply": "2025-07-16T16:48:09.425372Z", + "shell.execute_reply.started": "2025-07-16T16:48:09.404963Z" } }, "outputs": [ @@ -377,11 +378,11 @@ "id": "0db9be9f-5ce5-41dd-983f-0efd7d3b7002", "metadata": { "execution": { - "iopub.execute_input": "2025-07-11T18:13:04.924710Z", - "iopub.status.busy": "2025-07-11T18:13:04.924563Z", - "iopub.status.idle": "2025-07-11T18:13:04.929442Z", - "shell.execute_reply": "2025-07-11T18:13:04.928890Z", - "shell.execute_reply.started": "2025-07-11T18:13:04.924698Z" + "iopub.execute_input": "2025-07-16T16:48:09.427393Z", + "iopub.status.busy": "2025-07-16T16:48:09.427229Z", + "iopub.status.idle": "2025-07-16T16:48:09.434434Z", + "shell.execute_reply": "2025-07-16T16:48:09.433846Z", + "shell.execute_reply.started": "2025-07-16T16:48:09.427380Z" } }, "outputs": [ @@ -442,8 +443,8 @@ " obs_dir = None\n", " sas_ccf = None\n", " sas_odf = None\n", - " cifbuild_opts = []\n", - " odfingest_opts = []\n", + " cifbuild_opts = {}\n", + " odfingest_opts = {}\n", " recalibrate = False\n", "\n", "Input arguments for 'epproc', 'emproc', and 'rgsproc' can also be \n", @@ -531,11 +532,11 @@ "id": "e410cb47-508e-4e17-8160-fc226d350ab4", "metadata": { "execution": { - "iopub.execute_input": "2025-07-11T18:13:04.930064Z", - "iopub.status.busy": "2025-07-11T18:13:04.929945Z", - "iopub.status.idle": "2025-07-11T18:13:04.941635Z", - "shell.execute_reply": "2025-07-11T18:13:04.941057Z", - "shell.execute_reply.started": "2025-07-11T18:13:04.930055Z" + "iopub.execute_input": "2025-07-16T16:48:09.435295Z", + "iopub.status.busy": "2025-07-16T16:48:09.434934Z", + "iopub.status.idle": "2025-07-16T16:48:09.446791Z", + "shell.execute_reply": "2025-07-16T16:48:09.446143Z", + "shell.execute_reply.started": "2025-07-16T16:48:09.435279Z" } }, "outputs": [ @@ -639,11 +640,11 @@ "id": "7fe2957b-7dbf-47b3-b4d1-63edb7f08d41", "metadata": { "execution": { - "iopub.execute_input": "2025-07-11T18:13:04.942338Z", - "iopub.status.busy": "2025-07-11T18:13:04.942197Z", - "iopub.status.idle": "2025-07-11T18:13:04.954307Z", - "shell.execute_reply": "2025-07-11T18:13:04.953580Z", - "shell.execute_reply.started": "2025-07-11T18:13:04.942317Z" + "iopub.execute_input": "2025-07-16T16:48:09.447420Z", + "iopub.status.busy": "2025-07-16T16:48:09.447226Z", + "iopub.status.idle": "2025-07-16T16:48:09.458947Z", + "shell.execute_reply": "2025-07-16T16:48:09.458392Z", + "shell.execute_reply.started": "2025-07-16T16:48:09.447408Z" } }, "outputs": [ @@ -721,11 +722,11 @@ "id": "2efd7c03-68db-4155-9afd-6ffc5762f365", "metadata": { "execution": { - "iopub.execute_input": "2025-07-11T18:13:04.955239Z", - "iopub.status.busy": "2025-07-11T18:13:04.954933Z", - "iopub.status.idle": "2025-07-11T18:13:04.964100Z", - "shell.execute_reply": "2025-07-11T18:13:04.963334Z", - "shell.execute_reply.started": "2025-07-11T18:13:04.955224Z" + "iopub.execute_input": "2025-07-16T16:48:09.459955Z", + "iopub.status.busy": "2025-07-16T16:48:09.459792Z", + "iopub.status.idle": "2025-07-16T16:48:09.471553Z", + "shell.execute_reply": "2025-07-16T16:48:09.470798Z", + "shell.execute_reply.started": "2025-07-16T16:48:09.459942Z" } }, "outputs": [ @@ -754,11 +755,11 @@ "id": "c25c1558-d781-42f7-979e-b203b3703932", "metadata": { "execution": { - "iopub.execute_input": "2025-07-11T18:13:04.964785Z", - "iopub.status.busy": "2025-07-11T18:13:04.964583Z", - "iopub.status.idle": "2025-07-11T18:13:04.975193Z", - "shell.execute_reply": "2025-07-11T18:13:04.974607Z", - "shell.execute_reply.started": "2025-07-11T18:13:04.964773Z" + "iopub.execute_input": "2025-07-16T16:48:09.472312Z", + "iopub.status.busy": "2025-07-16T16:48:09.472157Z", + "iopub.status.idle": "2025-07-16T16:48:09.486037Z", + "shell.execute_reply": "2025-07-16T16:48:09.485403Z", + "shell.execute_reply.started": "2025-07-16T16:48:09.472300Z" } }, "outputs": [ @@ -771,8 +772,8 @@ "\u001b[0;34m\u001b[0m \u001b[0mobs_dir\u001b[0m\u001b[0;34m=\u001b[0m\u001b[0;32mNone\u001b[0m\u001b[0;34m,\u001b[0m\u001b[0;34m\u001b[0m\n", "\u001b[0;34m\u001b[0m \u001b[0msas_ccf\u001b[0m\u001b[0;34m=\u001b[0m\u001b[0;32mNone\u001b[0m\u001b[0;34m,\u001b[0m\u001b[0;34m\u001b[0m\n", "\u001b[0;34m\u001b[0m \u001b[0msas_odf\u001b[0m\u001b[0;34m=\u001b[0m\u001b[0;32mNone\u001b[0m\u001b[0;34m,\u001b[0m\u001b[0;34m\u001b[0m\n", - "\u001b[0;34m\u001b[0m \u001b[0mcifbuild_opts\u001b[0m\u001b[0;34m=\u001b[0m\u001b[0;34m[\u001b[0m\u001b[0;34m]\u001b[0m\u001b[0;34m,\u001b[0m\u001b[0;34m\u001b[0m\n", - "\u001b[0;34m\u001b[0m \u001b[0modfingest_opts\u001b[0m\u001b[0;34m=\u001b[0m\u001b[0;34m[\u001b[0m\u001b[0;34m]\u001b[0m\u001b[0;34m,\u001b[0m\u001b[0;34m\u001b[0m\n", + "\u001b[0;34m\u001b[0m \u001b[0mcifbuild_opts\u001b[0m\u001b[0;34m=\u001b[0m\u001b[0;34m{\u001b[0m\u001b[0;34m}\u001b[0m\u001b[0;34m,\u001b[0m\u001b[0;34m\u001b[0m\n", + "\u001b[0;34m\u001b[0m \u001b[0modfingest_opts\u001b[0m\u001b[0;34m=\u001b[0m\u001b[0;34m{\u001b[0m\u001b[0;34m}\u001b[0m\u001b[0;34m,\u001b[0m\u001b[0;34m\u001b[0m\n", "\u001b[0;34m\u001b[0m \u001b[0mrecalibrate\u001b[0m\u001b[0;34m=\u001b[0m\u001b[0;32mFalse\u001b[0m\u001b[0;34m,\u001b[0m\u001b[0;34m\u001b[0m\n", "\u001b[0;34m\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n", "\u001b[0;31mDocstring:\u001b[0m\n", @@ -835,11 +836,11 @@ "id": "596ea4cc-a450-45a7-a862-3f3316485332", "metadata": { "execution": { - "iopub.execute_input": "2025-07-11T18:13:04.975908Z", - "iopub.status.busy": "2025-07-11T18:13:04.975682Z", - "iopub.status.idle": "2025-07-11T18:13:04.985247Z", - "shell.execute_reply": "2025-07-11T18:13:04.984590Z", - "shell.execute_reply.started": "2025-07-11T18:13:04.975896Z" + "iopub.execute_input": "2025-07-16T16:48:09.486699Z", + "iopub.status.busy": "2025-07-16T16:48:09.486565Z", + "iopub.status.idle": "2025-07-16T16:48:09.497463Z", + "shell.execute_reply": "2025-07-16T16:48:09.496763Z", + "shell.execute_reply.started": "2025-07-16T16:48:09.486687Z" } }, "outputs": [ @@ -871,11 +872,11 @@ "id": "df1fec60-9f36-4d0a-83b0-9dd29261fda0", "metadata": { "execution": { - "iopub.execute_input": "2025-07-11T18:13:04.986265Z", - "iopub.status.busy": "2025-07-11T18:13:04.985836Z", - "iopub.status.idle": "2025-07-11T18:13:04.995810Z", - "shell.execute_reply": "2025-07-11T18:13:04.995097Z", - "shell.execute_reply.started": "2025-07-11T18:13:04.986247Z" + "iopub.execute_input": "2025-07-16T16:48:09.498460Z", + "iopub.status.busy": "2025-07-16T16:48:09.498069Z", + "iopub.status.idle": "2025-07-16T16:48:09.511091Z", + "shell.execute_reply": "2025-07-16T16:48:09.510449Z", + "shell.execute_reply.started": "2025-07-16T16:48:09.498443Z" } }, "outputs": [ @@ -913,11 +914,11 @@ "id": "aac9a26d-4c13-45b3-9ae5-73775c613ed4", "metadata": { "execution": { - "iopub.execute_input": "2025-07-11T18:13:04.997052Z", - "iopub.status.busy": "2025-07-11T18:13:04.996888Z", - "iopub.status.idle": "2025-07-11T18:13:05.005734Z", - "shell.execute_reply": "2025-07-11T18:13:05.005156Z", - "shell.execute_reply.started": "2025-07-11T18:13:04.997039Z" + "iopub.execute_input": "2025-07-16T16:48:09.511879Z", + "iopub.status.busy": "2025-07-16T16:48:09.511593Z", + "iopub.status.idle": "2025-07-16T16:48:09.522891Z", + "shell.execute_reply": "2025-07-16T16:48:09.522245Z", + "shell.execute_reply.started": "2025-07-16T16:48:09.511866Z" } }, "outputs": [ @@ -949,11 +950,11 @@ "id": "fed1d78f-e928-4b2e-90d4-85104003b43d", "metadata": { "execution": { - "iopub.execute_input": "2025-07-11T18:13:05.006572Z", - "iopub.status.busy": "2025-07-11T18:13:05.006287Z", - "iopub.status.idle": "2025-07-11T18:13:05.015969Z", - "shell.execute_reply": "2025-07-11T18:13:05.015443Z", - "shell.execute_reply.started": "2025-07-11T18:13:05.006557Z" + "iopub.execute_input": "2025-07-16T16:48:09.523634Z", + "iopub.status.busy": "2025-07-16T16:48:09.523462Z", + "iopub.status.idle": "2025-07-16T16:48:09.538345Z", + "shell.execute_reply": "2025-07-16T16:48:09.537482Z", + "shell.execute_reply.started": "2025-07-16T16:48:09.523621Z" } }, "outputs": [ @@ -980,11 +981,11 @@ "id": "8c04117c-4562-4c02-b4bb-00eae1e10c89", "metadata": { "execution": { - "iopub.execute_input": "2025-07-11T18:13:05.017412Z", - "iopub.status.busy": "2025-07-11T18:13:05.017130Z", - "iopub.status.idle": "2025-07-11T18:13:05.026013Z", - "shell.execute_reply": "2025-07-11T18:13:05.025419Z", - "shell.execute_reply.started": "2025-07-11T18:13:05.017399Z" + "iopub.execute_input": "2025-07-16T16:48:09.540074Z", + "iopub.status.busy": "2025-07-16T16:48:09.539894Z", + "iopub.status.idle": "2025-07-16T16:48:09.549759Z", + "shell.execute_reply": "2025-07-16T16:48:09.549048Z", + "shell.execute_reply.started": "2025-07-16T16:48:09.540060Z" } }, "outputs": [ diff --git a/obsid/obsid.py b/obsid/obsid.py index 822c581..25b62b5 100644 --- a/obsid/obsid.py +++ b/obsid/obsid.py @@ -312,8 +312,8 @@ def basic_setup(self, obs_dir = None sas_ccf = None sas_odf = None - cifbuild_opts = [] - odfingest_opts = [] + cifbuild_opts = {} + odfingest_opts = {} recalibrate = False Input arguments for 'epproc', 'emproc', and 'rgsproc' can also be @@ -460,38 +460,38 @@ def basic_setup(self, self.calibrate_odf(obs_dir = self.obs_dir, sas_ccf = kwargs.get('sas_ccf', None), sas_odf = kwargs.get('sas_odf', None), - cifbuild_opts = kwargs.get('cifbuild_opts', []), - odfingest_opts = kwargs.get('odfingest_opts', []), + cifbuild_opts = kwargs.get('cifbuild_opts', {}), + odfingest_opts = kwargs.get('odfingest_opts', {}), recalibrate = recalibrate) # Run basic processing if run_epproc and not run_epchain: self.__run_analysis('epproc', - kwargs.get('epproc_args', []), + kwargs.get('epproc_args', {}), rerun = rerun, logFile = 'epproc.log') if run_epchain: self.__run_analysis('epchain', - kwargs.get('epchain_args', []), + kwargs.get('epchain_args', {}), rerun = rerun, logFile = 'epchain.log') if run_emproc and not run_emchain: self.__run_analysis('emproc', - kwargs.get('emproc_args', []), + kwargs.get('emproc_args', {}), rerun = rerun, logFile = 'emproc.log') if run_emchain: self.__run_analysis('emchain', - kwargs.get('emchain_args', []), + kwargs.get('emchain_args', {}), rerun = rerun, logFile = 'emchain.log') if run_rgsproc: self.__run_analysis('rgsproc', - kwargs.get('rgsproc_args', []), + kwargs.get('rgsproc_args', {}), rerun = rerun, logFile = 'rgsproc.log') @@ -871,8 +871,8 @@ def calibrate_odf(self, obs_dir = None, sas_ccf = None, sas_odf = None, - cifbuild_opts = [], - odfingest_opts = [], + cifbuild_opts = {}, + odfingest_opts = {}, recalibrate = False): """ Before running this function an ObsID object must be created first. e.g. @@ -944,9 +944,9 @@ def calibrate_odf(self, # Deal with the rest of the inputs. self.files['sas_ccf'] = sas_ccf self.files['sas_odf'] = sas_odf - if cifbuild_opts is None: cifbuild_opts = [] + if cifbuild_opts is None: cifbuild_opts = {} self.cifbuild_opts = cifbuild_opts - if odfingest_opts is None: odfingest_opts = [] + if odfingest_opts is None: odfingest_opts = {} self.odfingest_opts = odfingest_opts os.chdir(self.obs_dir) diff --git a/sastask.py b/sastask.py index eeaba63..b91b7eb 100644 --- a/sastask.py +++ b/sastask.py @@ -161,7 +161,7 @@ def __init__(self, taskname, inargs, self.tasklogdir = tasklogdir self.output_to_terminal = output_to_terminal self.output_to_file = output_to_file - + # The logger object assigned here will only be used for log information # generated by pySAS. Log information generated by SAS tasks will not # be controled by this logger object. @@ -187,6 +187,23 @@ def __init__(self, taskname, inargs, # Insert empty string for options if not present if not 'options' in self.inargs.keys(): self.inargs['options'] = '' + for key in self.inargs.keys(): + # Safety check to see if a number was passed in. + if isinstance(self.inargs[key], numbers.Number): + self.inargs[key] = str(self.inargs[key]) + # Convert booleans to 'yes' and 'no' + if self.inargs[key] is bool: + if self.inargs[key]: + self.inargs[key] = 'yes' + else: + self.inargs[key] = 'no' + + # Check if inargs is a single string. If it is, then split + # it at all spaces. This is not fool proof! + # ***STRONGLY*** NOT RECOMMENDED + # (unless the input is very simple, such as '-h') + if isinstance(self.inargs, str): + self.inargs = self.inargs.split() # If inargs is a list, pick off all the options, then put # all other arguments into key-value pairs in the dictionary. @@ -226,10 +243,10 @@ def processargs(self): self.Exit = p.procopt() if self.Exit: return self.Exit - + # Remove the options from inargs - self.argsdic = self.inargs.pop('options', None) - + self.argsdic = self.inargs + self.argsdic.pop('options') # 1st check: Whether or not parameters in inargs are defined in the parameter file for p in self.argsdic.keys(): From b723d89dd4004fcdbfd77f872bb29f70ca081c14 Mon Sep 17 00:00:00 2001 From: rjtanner Date: Wed, 16 Jul 2025 13:34:21 -0400 Subject: [PATCH 08/17] Update documentation --- .../Using_pySASv2-checkpoint.ipynb | 134 +++++++++--------- documentation/Using_pySASv2.ipynb | 1 + logger.py | 10 +- obsid/obsid.py | 2 +- sastask.py | 6 +- 5 files changed, 78 insertions(+), 75 deletions(-) diff --git a/documentation/.ipynb_checkpoints/Using_pySASv2-checkpoint.ipynb b/documentation/.ipynb_checkpoints/Using_pySASv2-checkpoint.ipynb index ee7e1b6..e844470 100644 --- a/documentation/.ipynb_checkpoints/Using_pySASv2-checkpoint.ipynb +++ b/documentation/.ipynb_checkpoints/Using_pySASv2-checkpoint.ipynb @@ -45,6 +45,8 @@ "Key changes:\n", " - `ObsID` is the new `ODFobject`\n", " - The `Wrapper` has been deprecated and replaced by `MyTask`\n", + " - `MyTask` now accepts the options `output_to_terminal` and `output_to_file`\n", + " - Input arguments can be passed in as either a dictionary or a list\n", "\n", "To implement these changes make the following modifications to your code:\n", "\n", @@ -211,8 +213,8 @@ "calibrate_odf(obs_dir = None,\n", " sas_ccf = None,\n", " sas_odf = None,\n", - " cifbuild_opts = [],\n", - " odfingest_opts = [],\n", + " cifbuild_opts = {},\n", + " odfingest_opts = {},\n", " recalibrate = False)\n", "\n", "get_active_instruments()\n", @@ -283,11 +285,11 @@ "id": "15b25239-d5ef-48a6-bb26-6fa4296ed2de", "metadata": { "execution": { - "iopub.execute_input": "2025-07-11T18:13:04.504348Z", - "iopub.status.busy": "2025-07-11T18:13:04.504233Z", - "iopub.status.idle": "2025-07-11T18:13:04.903347Z", - "shell.execute_reply": "2025-07-11T18:13:04.902834Z", - "shell.execute_reply.started": "2025-07-11T18:13:04.504336Z" + "iopub.execute_input": "2025-07-16T16:48:08.985884Z", + "iopub.status.busy": "2025-07-16T16:48:08.985775Z", + "iopub.status.idle": "2025-07-16T16:48:09.404326Z", + "shell.execute_reply": "2025-07-16T16:48:09.403577Z", + "shell.execute_reply.started": "2025-07-16T16:48:08.985872Z" } }, "outputs": [], @@ -309,11 +311,11 @@ "id": "7bbe67c0-6e5a-43ad-a0c2-ead5dd806e38", "metadata": { "execution": { - "iopub.execute_input": "2025-07-11T18:13:04.903993Z", - "iopub.status.busy": "2025-07-11T18:13:04.903868Z", - "iopub.status.idle": "2025-07-11T18:13:04.923423Z", - "shell.execute_reply": "2025-07-11T18:13:04.922811Z", - "shell.execute_reply.started": "2025-07-11T18:13:04.903982Z" + "iopub.execute_input": "2025-07-16T16:48:09.404973Z", + "iopub.status.busy": "2025-07-16T16:48:09.404840Z", + "iopub.status.idle": "2025-07-16T16:48:09.426058Z", + "shell.execute_reply": "2025-07-16T16:48:09.425372Z", + "shell.execute_reply.started": "2025-07-16T16:48:09.404963Z" } }, "outputs": [ @@ -377,11 +379,11 @@ "id": "0db9be9f-5ce5-41dd-983f-0efd7d3b7002", "metadata": { "execution": { - "iopub.execute_input": "2025-07-11T18:13:04.924710Z", - "iopub.status.busy": "2025-07-11T18:13:04.924563Z", - "iopub.status.idle": "2025-07-11T18:13:04.929442Z", - "shell.execute_reply": "2025-07-11T18:13:04.928890Z", - "shell.execute_reply.started": "2025-07-11T18:13:04.924698Z" + "iopub.execute_input": "2025-07-16T16:48:09.427393Z", + "iopub.status.busy": "2025-07-16T16:48:09.427229Z", + "iopub.status.idle": "2025-07-16T16:48:09.434434Z", + "shell.execute_reply": "2025-07-16T16:48:09.433846Z", + "shell.execute_reply.started": "2025-07-16T16:48:09.427380Z" } }, "outputs": [ @@ -442,8 +444,8 @@ " obs_dir = None\n", " sas_ccf = None\n", " sas_odf = None\n", - " cifbuild_opts = []\n", - " odfingest_opts = []\n", + " cifbuild_opts = {}\n", + " odfingest_opts = {}\n", " recalibrate = False\n", "\n", "Input arguments for 'epproc', 'emproc', and 'rgsproc' can also be \n", @@ -531,11 +533,11 @@ "id": "e410cb47-508e-4e17-8160-fc226d350ab4", "metadata": { "execution": { - "iopub.execute_input": "2025-07-11T18:13:04.930064Z", - "iopub.status.busy": "2025-07-11T18:13:04.929945Z", - "iopub.status.idle": "2025-07-11T18:13:04.941635Z", - "shell.execute_reply": "2025-07-11T18:13:04.941057Z", - "shell.execute_reply.started": "2025-07-11T18:13:04.930055Z" + "iopub.execute_input": "2025-07-16T16:48:09.435295Z", + "iopub.status.busy": "2025-07-16T16:48:09.434934Z", + "iopub.status.idle": "2025-07-16T16:48:09.446791Z", + "shell.execute_reply": "2025-07-16T16:48:09.446143Z", + "shell.execute_reply.started": "2025-07-16T16:48:09.435279Z" } }, "outputs": [ @@ -639,11 +641,11 @@ "id": "7fe2957b-7dbf-47b3-b4d1-63edb7f08d41", "metadata": { "execution": { - "iopub.execute_input": "2025-07-11T18:13:04.942338Z", - "iopub.status.busy": "2025-07-11T18:13:04.942197Z", - "iopub.status.idle": "2025-07-11T18:13:04.954307Z", - "shell.execute_reply": "2025-07-11T18:13:04.953580Z", - "shell.execute_reply.started": "2025-07-11T18:13:04.942317Z" + "iopub.execute_input": "2025-07-16T16:48:09.447420Z", + "iopub.status.busy": "2025-07-16T16:48:09.447226Z", + "iopub.status.idle": "2025-07-16T16:48:09.458947Z", + "shell.execute_reply": "2025-07-16T16:48:09.458392Z", + "shell.execute_reply.started": "2025-07-16T16:48:09.447408Z" } }, "outputs": [ @@ -721,11 +723,11 @@ "id": "2efd7c03-68db-4155-9afd-6ffc5762f365", "metadata": { "execution": { - "iopub.execute_input": "2025-07-11T18:13:04.955239Z", - "iopub.status.busy": "2025-07-11T18:13:04.954933Z", - "iopub.status.idle": "2025-07-11T18:13:04.964100Z", - "shell.execute_reply": "2025-07-11T18:13:04.963334Z", - "shell.execute_reply.started": "2025-07-11T18:13:04.955224Z" + "iopub.execute_input": "2025-07-16T16:48:09.459955Z", + "iopub.status.busy": "2025-07-16T16:48:09.459792Z", + "iopub.status.idle": "2025-07-16T16:48:09.471553Z", + "shell.execute_reply": "2025-07-16T16:48:09.470798Z", + "shell.execute_reply.started": "2025-07-16T16:48:09.459942Z" } }, "outputs": [ @@ -754,11 +756,11 @@ "id": "c25c1558-d781-42f7-979e-b203b3703932", "metadata": { "execution": { - "iopub.execute_input": "2025-07-11T18:13:04.964785Z", - "iopub.status.busy": "2025-07-11T18:13:04.964583Z", - "iopub.status.idle": "2025-07-11T18:13:04.975193Z", - "shell.execute_reply": "2025-07-11T18:13:04.974607Z", - "shell.execute_reply.started": "2025-07-11T18:13:04.964773Z" + "iopub.execute_input": "2025-07-16T16:48:09.472312Z", + "iopub.status.busy": "2025-07-16T16:48:09.472157Z", + "iopub.status.idle": "2025-07-16T16:48:09.486037Z", + "shell.execute_reply": "2025-07-16T16:48:09.485403Z", + "shell.execute_reply.started": "2025-07-16T16:48:09.472300Z" } }, "outputs": [ @@ -771,8 +773,8 @@ "\u001b[0;34m\u001b[0m \u001b[0mobs_dir\u001b[0m\u001b[0;34m=\u001b[0m\u001b[0;32mNone\u001b[0m\u001b[0;34m,\u001b[0m\u001b[0;34m\u001b[0m\n", "\u001b[0;34m\u001b[0m \u001b[0msas_ccf\u001b[0m\u001b[0;34m=\u001b[0m\u001b[0;32mNone\u001b[0m\u001b[0;34m,\u001b[0m\u001b[0;34m\u001b[0m\n", "\u001b[0;34m\u001b[0m \u001b[0msas_odf\u001b[0m\u001b[0;34m=\u001b[0m\u001b[0;32mNone\u001b[0m\u001b[0;34m,\u001b[0m\u001b[0;34m\u001b[0m\n", - "\u001b[0;34m\u001b[0m \u001b[0mcifbuild_opts\u001b[0m\u001b[0;34m=\u001b[0m\u001b[0;34m[\u001b[0m\u001b[0;34m]\u001b[0m\u001b[0;34m,\u001b[0m\u001b[0;34m\u001b[0m\n", - "\u001b[0;34m\u001b[0m \u001b[0modfingest_opts\u001b[0m\u001b[0;34m=\u001b[0m\u001b[0;34m[\u001b[0m\u001b[0;34m]\u001b[0m\u001b[0;34m,\u001b[0m\u001b[0;34m\u001b[0m\n", + "\u001b[0;34m\u001b[0m \u001b[0mcifbuild_opts\u001b[0m\u001b[0;34m=\u001b[0m\u001b[0;34m{\u001b[0m\u001b[0;34m}\u001b[0m\u001b[0;34m,\u001b[0m\u001b[0;34m\u001b[0m\n", + "\u001b[0;34m\u001b[0m \u001b[0modfingest_opts\u001b[0m\u001b[0;34m=\u001b[0m\u001b[0;34m{\u001b[0m\u001b[0;34m}\u001b[0m\u001b[0;34m,\u001b[0m\u001b[0;34m\u001b[0m\n", "\u001b[0;34m\u001b[0m \u001b[0mrecalibrate\u001b[0m\u001b[0;34m=\u001b[0m\u001b[0;32mFalse\u001b[0m\u001b[0;34m,\u001b[0m\u001b[0;34m\u001b[0m\n", "\u001b[0;34m\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n", "\u001b[0;31mDocstring:\u001b[0m\n", @@ -835,11 +837,11 @@ "id": "596ea4cc-a450-45a7-a862-3f3316485332", "metadata": { "execution": { - "iopub.execute_input": "2025-07-11T18:13:04.975908Z", - "iopub.status.busy": "2025-07-11T18:13:04.975682Z", - "iopub.status.idle": "2025-07-11T18:13:04.985247Z", - "shell.execute_reply": "2025-07-11T18:13:04.984590Z", - "shell.execute_reply.started": "2025-07-11T18:13:04.975896Z" + "iopub.execute_input": "2025-07-16T16:48:09.486699Z", + "iopub.status.busy": "2025-07-16T16:48:09.486565Z", + "iopub.status.idle": "2025-07-16T16:48:09.497463Z", + "shell.execute_reply": "2025-07-16T16:48:09.496763Z", + "shell.execute_reply.started": "2025-07-16T16:48:09.486687Z" } }, "outputs": [ @@ -871,11 +873,11 @@ "id": "df1fec60-9f36-4d0a-83b0-9dd29261fda0", "metadata": { "execution": { - "iopub.execute_input": "2025-07-11T18:13:04.986265Z", - "iopub.status.busy": "2025-07-11T18:13:04.985836Z", - "iopub.status.idle": "2025-07-11T18:13:04.995810Z", - "shell.execute_reply": "2025-07-11T18:13:04.995097Z", - "shell.execute_reply.started": "2025-07-11T18:13:04.986247Z" + "iopub.execute_input": "2025-07-16T16:48:09.498460Z", + "iopub.status.busy": "2025-07-16T16:48:09.498069Z", + "iopub.status.idle": "2025-07-16T16:48:09.511091Z", + "shell.execute_reply": "2025-07-16T16:48:09.510449Z", + "shell.execute_reply.started": "2025-07-16T16:48:09.498443Z" } }, "outputs": [ @@ -913,11 +915,11 @@ "id": "aac9a26d-4c13-45b3-9ae5-73775c613ed4", "metadata": { "execution": { - "iopub.execute_input": "2025-07-11T18:13:04.997052Z", - "iopub.status.busy": "2025-07-11T18:13:04.996888Z", - "iopub.status.idle": "2025-07-11T18:13:05.005734Z", - "shell.execute_reply": "2025-07-11T18:13:05.005156Z", - "shell.execute_reply.started": "2025-07-11T18:13:04.997039Z" + "iopub.execute_input": "2025-07-16T16:48:09.511879Z", + "iopub.status.busy": "2025-07-16T16:48:09.511593Z", + "iopub.status.idle": "2025-07-16T16:48:09.522891Z", + "shell.execute_reply": "2025-07-16T16:48:09.522245Z", + "shell.execute_reply.started": "2025-07-16T16:48:09.511866Z" } }, "outputs": [ @@ -949,11 +951,11 @@ "id": "fed1d78f-e928-4b2e-90d4-85104003b43d", "metadata": { "execution": { - "iopub.execute_input": "2025-07-11T18:13:05.006572Z", - "iopub.status.busy": "2025-07-11T18:13:05.006287Z", - "iopub.status.idle": "2025-07-11T18:13:05.015969Z", - "shell.execute_reply": "2025-07-11T18:13:05.015443Z", - "shell.execute_reply.started": "2025-07-11T18:13:05.006557Z" + "iopub.execute_input": "2025-07-16T16:48:09.523634Z", + "iopub.status.busy": "2025-07-16T16:48:09.523462Z", + "iopub.status.idle": "2025-07-16T16:48:09.538345Z", + "shell.execute_reply": "2025-07-16T16:48:09.537482Z", + "shell.execute_reply.started": "2025-07-16T16:48:09.523621Z" } }, "outputs": [ @@ -980,11 +982,11 @@ "id": "8c04117c-4562-4c02-b4bb-00eae1e10c89", "metadata": { "execution": { - "iopub.execute_input": "2025-07-11T18:13:05.017412Z", - "iopub.status.busy": "2025-07-11T18:13:05.017130Z", - "iopub.status.idle": "2025-07-11T18:13:05.026013Z", - "shell.execute_reply": "2025-07-11T18:13:05.025419Z", - "shell.execute_reply.started": "2025-07-11T18:13:05.017399Z" + "iopub.execute_input": "2025-07-16T16:48:09.540074Z", + "iopub.status.busy": "2025-07-16T16:48:09.539894Z", + "iopub.status.idle": "2025-07-16T16:48:09.549759Z", + "shell.execute_reply": "2025-07-16T16:48:09.549048Z", + "shell.execute_reply.started": "2025-07-16T16:48:09.540060Z" } }, "outputs": [ diff --git a/documentation/Using_pySASv2.ipynb b/documentation/Using_pySASv2.ipynb index 0d5d185..e844470 100644 --- a/documentation/Using_pySASv2.ipynb +++ b/documentation/Using_pySASv2.ipynb @@ -45,6 +45,7 @@ "Key changes:\n", " - `ObsID` is the new `ODFobject`\n", " - The `Wrapper` has been deprecated and replaced by `MyTask`\n", + " - `MyTask` now accepts the options `output_to_terminal` and `output_to_file`\n", " - Input arguments can be passed in as either a dictionary or a list\n", "\n", "To implement these changes make the following modifications to your code:\n", diff --git a/logger.py b/logger.py index cffd1e3..0e46647 100644 --- a/logger.py +++ b/logger.py @@ -136,16 +136,16 @@ def get_logger(taskname: str, level=level, mode=sastasklogfmode, enqueue=True, - format="{time:DD-MM-YYYY HH:mm:ss.SSS Z} - {name} - {level: <8} - {message}" + format="{time:DD-MM-YYYY HH:mm:ss.SSS Z} - {name} - {level: <8} - {message}" ) # Add console sink if toterminal: task_logger.add( - sink=sys.stderr, + sink=sys.stdout, level=level, enqueue=True, - format="{name} - {level: <8} - {message}" + format="{name} - {level: <8} - {message}" ) else: # For non-Python based logging (i.e. subprocess) @@ -160,7 +160,7 @@ def get_logger(taskname: str, level=level, mode=sastasklogfmode, enqueue=True, - format="{time:DD-MM-YYYY HH:mm:ss.SSS Z} - {message}" + format="{time:DD-MM-YYYY HH:mm:ss.SSS Z} - {message}" ) # Add console sink @@ -169,7 +169,7 @@ def get_logger(taskname: str, sink=sys.stdout, level=level, enqueue=True, - format="{message}", + format="{message}", ) return task_logger diff --git a/obsid/obsid.py b/obsid/obsid.py index 25b62b5..05f0e92 100644 --- a/obsid/obsid.py +++ b/obsid/obsid.py @@ -1239,7 +1239,7 @@ def get_ccf_cif(self): self.logger.info('{0} is present'.format(self.files['sas_ccf'])) exists = True else: - self.logger.warning('ccf.cif file not present! User must run calibrate_odf!') + self.logger.info('ccf.cif file not present! User must run calibrate_odf!') return exists diff --git a/sastask.py b/sastask.py index b91b7eb..d959521 100644 --- a/sastask.py +++ b/sastask.py @@ -427,15 +427,15 @@ def run(self): shell=True, text=True, stdout=subprocess.PIPE, - stderr=subprocess.PIPE, + stderr=subprocess.STDOUT, universal_newlines=True) # Log stdout and stderr in real-time # For non-Python SAS tasks the stout and stderr are combined for line in process.stdout: logger.info(f"{line.strip()}") - for line in process.stderr: - logger.info(f"{line.strip()}") + # for line in process.stderr: + # logger.info(f"{line.strip()}") # Wait for the process to complete and get the return code process.wait() From b50fccb5a20425d1d0a7454b530d0282248e0f92 Mon Sep 17 00:00:00 2001 From: rjtanner Date: Wed, 16 Jul 2025 16:26:07 -0400 Subject: [PATCH 09/17] Update ChangeLog --- ChangeLog | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/ChangeLog b/ChangeLog index defdc00..e4124c3 100644 --- a/ChangeLog +++ b/ChangeLog @@ -57,14 +57,11 @@ Version 2.0 - 2025-??-?? (RT) they cannot be used by the end user. + obsid : obsid.py introduced. Replaces odfcontrol. - Significant changes to pySAS. Three new classes (Parent with two children): - 1. ObsID (Parent class) - 2. ODF (Child class of ObsID) - 3. PPS (Child class of ObsID) + Significant changes to pySAS. New class: ObsID + parser.py : Update documentation, add logger to ParseArgs, changed 'taskparser' to 'optparser'. -+ param.py : Update documentation, add logger to paramXmlInfoReader ++ param.py : Update documentation, add logger to paramXmlInfoReader. From 7099fa47ea8ca2d90198242f1e82e625067519b3 Mon Sep 17 00:00:00 2001 From: rjtanner Date: Thu, 17 Jul 2025 14:48:48 -0400 Subject: [PATCH 10/17] Add quick_eplot --- ..._guide_images_and_filters-checkpoint.ipynb | 892 ++++++++++++++++++ .../xmm_ABC_guide_images_and_filters.ipynb | 2 +- obsid/obsid.py | 56 +- parser.py | 12 +- pysasplot_utils/pysasplot_utils.py | 39 +- pyutils/pyutils.py | 6 +- sastask.py | 30 +- 7 files changed, 1001 insertions(+), 36 deletions(-) create mode 100644 documentation/Jupyter_Notebooks/.ipynb_checkpoints/xmm_ABC_guide_images_and_filters-checkpoint.ipynb diff --git a/documentation/Jupyter_Notebooks/.ipynb_checkpoints/xmm_ABC_guide_images_and_filters-checkpoint.ipynb b/documentation/Jupyter_Notebooks/.ipynb_checkpoints/xmm_ABC_guide_images_and_filters-checkpoint.ipynb new file mode 100644 index 0000000..92b2b7a --- /dev/null +++ b/documentation/Jupyter_Notebooks/.ipynb_checkpoints/xmm_ABC_guide_images_and_filters-checkpoint.ipynb @@ -0,0 +1,892 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "id": "95220aeb-e7d6-43ba-9f8f-a83b7f62ccb2", + "metadata": {}, + "source": [ + "# ABC Guide for XMM-Newton -- Images and Basic Filtering (Intro to pySAS Part 1)\n", + "\n", + "---\n", + "\n", + "#### Introduction\n", + "This tutorial is based on Chapter 6 from the [The XMM-Newton ABC Guide](https://heasarc.gsfc.nasa.gov/docs/xmm/abc/ \"ABC Guide\") prepared by the NASA/GSFC XMM-Newton Guest Observer Facility. This notebook assumes you are using the version of pySAS that can be installed using `pip` or the version found on [GitHub](https://github.com/XMMGOF/pysas) and have already configured it to work with your SAS installation (see the [README on GitHub](https://github.com/XMMGOF/pysas/blob/main/README.md)). \n", + "#### Expected Outcome\n", + "The ability to apply basic filters to any XMM-Newton observation and prepare it for analysis.\n", + "#### SAS Tasks to be Used\n", + "\n", + "- `emproc`[(Documentation for emproc)](https://xmm-tools.cosmos.esa.int/external/sas/current/doc/emproc/index.html \"emproc Documentation\")\n", + "- `epproc`[(Documentation for epproc)](https://xmm-tools.cosmos.esa.int/external/sas/current/doc/epproc/index.html \"epproc Documentation\")\n", + "- `evselect`[(Documentation for evselect)](https://xmm-tools.cosmos.esa.int/external/sas/current/doc/evselect/index.html)\n", + "- `tabgtigen`[(Documentation for tabgtigen)](https://xmm-tools.cosmos.esa.int/external/sas/current/doc/tabgtigen/index.html)\n", + "- `gtibuild`[(Documentation for gtibuild)](https://xmm-tools.cosmos.esa.int/external/sas/current/doc/gtibuild/index.html)\n", + "\n", + "#### Prerequisites\n", + "
\n", + " Note: Before running this notebook, or even starting a Jupyter Lab session, HEASOFT has to be initialized. If you did not initalize HEASOFT before starting this Jupyter Lab session, or opening this notebook, please close this window and initalize HEASOFT (it is not possible to initalize HEASOFT from within a Jupyter Notebook). SAS defaults will need to be set as explained in the README on GitHub (https://github.com/XMMGOF/pysas/blob/main/README.md).\n", + "
\n", + "\n", + "#### Useful Links\n", + "\n", + "- [`pysas` Documentation](https://xmm-tools.cosmos.esa.int/external/sas/current/doc/pysas/index.html \"pysas Documentation\")\n", + "- [`pysas` on GitHub](https://github.com/XMMGOF/pysas)\n", + "- [Common SAS Threads](https://www.cosmos.esa.int/web/xmm-newton/sas-threads \"SAS Threads\")\n", + "- [Users' Guide to the XMM-Newton Science Analysis System (SAS)](https://xmm-tools.cosmos.esa.int/external/xmm_user_support/documentation/sas_usg/USG/SASUSG.html \"Users' Guide\")\n", + "- [The XMM-Newton ABC Guide](https://heasarc.gsfc.nasa.gov/docs/xmm/abc/ \"ABC Guide\")\n", + "- [XMM Newton GOF Helpdesk](https://heasarc.gsfc.nasa.gov/docs/xmm/xmm_helpdesk.html \"Helpdesk\") - Link to form to contact the GOF Helpdesk.\n", + "\n", + "#### Caveats\n", + "This tutorial uses an observation of the Lockman Hole (obsid = '0123700101')." + ] + }, + { + "cell_type": "markdown", + "id": "7eebc609-8d0a-40be-a848-cc6abf26f406", + "metadata": {}, + "source": [ + "##### Last Reviewed: _1 January 2025, for SAS v21 and pySAS v1.4.5_\n", + "##### Last Updated: _1 January 2025_\n", + "##### By: Ryan Tanner (ryan.tanner@nasa.gov)\n", + "---" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "c36c8366-38cb-4a4f-ad8c-75937fe0484a", + "metadata": {}, + "outputs": [], + "source": [ + "# pySAS imports\n", + "import pysas\n", + "from pysas.wrapper import Wrapper as w\n", + "\n", + "# Useful imports\n", + "import os\n", + "\n", + "# Imports for plotting\n", + "import matplotlib.pyplot as plt\n", + "from astropy.visualization import astropy_mpl_style\n", + "from astropy.io import fits\n", + "from astropy.wcs import WCS\n", + "from astropy.table import Table\n", + "plt.style.use(astropy_mpl_style)" + ] + }, + { + "cell_type": "markdown", + "id": "4a8b6683-eb97-4ed6-8530-41712367eebb", + "metadata": {}, + "source": [ + "### 6.1 : Rerun basic processing" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "3b52b56f-e3a3-4109-ab96-426130531578", + "metadata": { + "scrolled": true, + "tags": [] + }, + "outputs": [], + "source": [ + "obsid = '0123700101'\n", + "odf = pysas.odfcontrol.ODFobject(obsid)\n", + "odf.basic_setup(overwrite=False,repo='heasarc',\n", + " rerun=False, epproc_args=['withoutoftime=yes'])" + ] + }, + { + "cell_type": "markdown", + "id": "c8e45876-d6cb-4f7a-9975-6f1dbeb42e15", + "metadata": {}, + "source": [ + "If the dataset has more than one exposure, a specific exposure can be accessed using the withinstexpids and instexpids parameters, e.g.:\n", + "\n", + "```python\n", + "inargs = \"withinstexpids=yes instexpids='M1S001 M2S001'\"\n", + "w('emproc', inargs).run()\n", + "```\n", + "\n", + "
\n", + " Note: For PN observations with very bright sources, out-of-time events can provide a serious contamination of the image. Out-of-time events occur because the read-out period for the CCDs can be up to $\\sim6.3$% of the frame time. Since events that occur during the read-out period can't be distinguished from others events, they are included in the event files but have invalid locations. For observations with bright sources, this can cause bright stripes in the image along the CCD read-out direction.\n", + "
\n", + "\n", + "To create an out-of-time event file for your PN data, add the parameter withoutoftime to your epproc invocation:\n", + "\n", + "```python\n", + "inargs = \"withoutoftime=yes\"\n", + "w('epproc', inargs).run()\n", + "```\n", + "\n", + "By default, these tasks do not keep any intermediate files they generate. Emproc and epproc designate their output event files with \"*ImagingEvts.ds\"." + ] + }, + { + "cell_type": "markdown", + "id": "15b8c1fe-3fc9-48af-97c6-7e7cbdea4ab5", + "metadata": {}, + "source": [ + "### 6.2 : Plot image" + ] + }, + { + "cell_type": "markdown", + "id": "95bc5614-c845-48be-8d41-b210a9a7ee91", + "metadata": {}, + "source": [ + "Below we define a useful function to make image plotting easier. It uses `evselect` to create a FITS image file from a FITS event list file. As a default it creates a file named \"image.fits\" and this file will be overwritten each time the function is called. If you want your image file to have a unique name then use the function input \"image_file\". For example:\n", + "\n", + "```python\n", + "make_fits_image('event_list_file.fits', image_file='my_special_image.fits')\n", + "```\n", + "---\n", + "The input arguments to `evselect` to create a FITS image file are:\n", + "\n", + " table - input event list file name\n", + " withimageset - make an image\n", + " imageset - name of output image file\n", + " xcolumn - event column for X axis\n", + " ycolumn - event column for Y axis\n", + " imagebinning - form of binning, force entire image into a given size or bin by a specified number of pixels\n", + " ximagesize - output image pixels in X\n", + " yimagesize - output image pixels in Y" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "f91b9cfc-8467-479c-b8c6-61bec06f6c12", + "metadata": {}, + "outputs": [], + "source": [ + "def make_fits_image(event_list_file, image_file='image.fits'):\n", + " \n", + " inargs = ['table={0}'.format(event_list_file), \n", + " 'withimageset=yes',\n", + " 'imageset={0}'.format(image_file), \n", + " 'xcolumn=X', \n", + " 'ycolumn=Y', \n", + " 'imagebinning=imageSize', \n", + " 'ximagesize=600', \n", + " 'yimagesize=600']\n", + "\n", + " w('evselect', inargs).run()\n", + "\n", + " hdu = fits.open(image_file)[0]\n", + " wcs = WCS(hdu.header)\n", + "\n", + " ax = plt.subplot(projection=wcs)\n", + " plt.imshow(hdu.data, origin='lower', norm='log', vmin=1.0, vmax=1e2)\n", + " ax.set_facecolor(\"black\")\n", + " plt.grid(color='blue', ls='solid')\n", + " plt.xlabel('RA')\n", + " plt.ylabel('Dec')\n", + " plt.colorbar()\n", + " plt.show()" + ] + }, + { + "cell_type": "markdown", + "id": "1402d8fe-c196-48dd-bfeb-e90902c959ba", + "metadata": {}, + "source": [ + "We also define a function to make plotting light curves simpler. As with the function `make_fits_image` it uses `evselect` to create the light curve. It also creates a default light curve FITS file.\n", + "\n", + "---\n", + "The input arguments to `evselect` to create a light curve file are:\n", + "\n", + " table - input event table\n", + " withrateset - make a light curve\n", + " rateset - name of output light curve file\n", + " maketimecolumn - control to create a time column\n", + " timecolumn - time column label\n", + " timebinsize - time binning (seconds)\n", + " makeratecolumn - control to create a count rate column, otherwise a count column will be created\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "e6f98330-8c09-4c13-acf1-f59d95d9fbd0", + "metadata": {}, + "outputs": [], + "source": [ + "def plot_light_curve(event_list_file, light_curve_file='ltcrv.fits'):\n", + " \n", + " inargs = ['table={0}'.format(event_list_file), \n", + " 'withrateset=yes', \n", + " 'rateset={0}'.format(light_curve_file), \n", + " 'maketimecolumn=yes', \n", + " 'timecolumn=TIME', \n", + " 'timebinsize=100', \n", + " 'makeratecolumn=yes']\n", + "\n", + " w('evselect', inargs).run()\n", + "\n", + " ts = Table.read(light_curve_file,hdu=1)\n", + " plt.plot(ts['TIME'],ts['RATE'])\n", + " plt.xlabel('Time (s)')\n", + " plt.ylabel('Count Rate (ct/s)')\n", + " plt.show()" + ] + }, + { + "cell_type": "markdown", + "id": "8d68d9c3-396e-4ced-8475-ef30d378ecd8", + "metadata": {}, + "source": [ + "We need to change into the work directory to run the next SAS tasks. We also get the name and path to the event list file created in §6.1." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "1968b75e-9296-4d6b-aad3-3a6881453c4e", + "metadata": { + "tags": [] + }, + "outputs": [], + "source": [ + "os.chdir(odf.work_dir)\n", + "mos1 = odf.files['M1evt_list'][0]" + ] + }, + { + "cell_type": "markdown", + "id": "cddbecc3-35cf-4e63-a58e-fe11273fa8f6", + "metadata": {}, + "source": [ + "Here we plot an image of the raw data with no filters applied. The image should be very noisy." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "b8a82f49-b916-41f4-8325-11849969db9a", + "metadata": { + "scrolled": true + }, + "outputs": [], + "source": [ + "make_fits_image(mos1)" + ] + }, + { + "cell_type": "markdown", + "id": "38dc5e2e-53f9-436f-bb13-5db71d9c3f9a", + "metadata": {}, + "source": [ + "### 6.3 : Apply Standard Filter" + ] + }, + { + "cell_type": "markdown", + "id": "5e9c4470-1425-49cf-b9a8-b03844c3e9f0", + "metadata": {}, + "source": [ + "To begin we apply a standard filter. The filtering expressions for the MOS and PN are, respectively:\n", + "```\n", + "(PATTERN $<=$ 12)&&(PI in [200:12000])&&#XMMEA_EM\n", + "```\n", + "and\n", + "```\n", + "(PATTERN $<=$ 4)&&(PI in [200:15000])&&#XMMEA_EP\n", + "```\n", + "The first two expressions will select good events with `PATTERN` in the 0 to 12 (or 0 to 4) range. The `PATTERN` value is similar the `GRADE` selection for ASCA data, and is related to the number and pattern of the CCD pixels triggered for a given event. The `PATTERN` assignments are: single pixel events: `PATTERN == 0`, double pixel events: `PATTERN in [1:4]`, triple and quadruple events: `PATTERN in [5:12]`.\n", + "\n", + "The second keyword in the expressions, `PI`, selects the preferred pulse height of the event; for the MOS, this should be between 200 and 12000 eV. For the PN, this should be between 200 and 15000 eV. This should clean up the image significantly with most of the rest of the obvious contamination due to low pulse height events. Setting the lower `PI` channel limit somewhat higher (e.g., to 300 eV) will eliminate much of the rest.\n", + "\n", + "Finally, the `#XMMEA_EM` (`#XMMEA_EP` for the PN) filter provides a canned screening set of `FLAG` values for the event. The `FLAG` value provides a bit encoding of various event conditions, e.g., near hot pixels or outside of the field of view. Setting `FLAG == 0` in the selection expression provides the most conservative screening criteria and should always be used when serious spectral analysis is to be done on the PN. It typically is not necessary for the MOS.\n", + "\n", + "It is a good idea to keep the output filtered event files and use them in your analyses, as opposed to re-filtering the original file with every task. This will save much time and computer memory. As an example, the Lockman Hole data's original event file is 48.4 Mb; the fully filtered list (that is, filtered spatially, temporally, and spectrally) is only 4.0Mb!\n", + "\n", + "The input arguments to `evselect` to apply the filter are:\n", + "\n", + " table - input event table\n", + " filtertype - method of filtering\n", + " expression - filtering expression\n", + " withfilteredset - create a filtered set\n", + " filteredset - output file name\n", + " keepfilteroutput - save the filtered output\n", + " updateexposure - update exposure information in event list and in spectrum files\n", + " filterexposure - filter exposure extensions of event list with same time" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "a81bf645-ed6c-41b3-a223-276522d475d9", + "metadata": { + "scrolled": true, + "tags": [] + }, + "outputs": [], + "source": [ + "filtered_event_list = 'mos1_filt.fits'\n", + "\n", + "inargs = ['table={0}'.format(mos1), \n", + " 'withfilteredset=yes', \n", + " \"expression='(PATTERN <= 12)&&(PI in [200:4000])&&#XMMEA_EM'\", \n", + " 'filteredset={0}'.format(filtered_event_list), \n", + " 'filtertype=expression', \n", + " 'keepfilteroutput=yes', \n", + " 'updateexposure=yes', \n", + " 'filterexposure=yes']\n", + "\n", + "w('evselect', inargs).run()" + ] + }, + { + "cell_type": "markdown", + "id": "1666439d-cefc-417f-a65e-aef85f8f4867", + "metadata": {}, + "source": [ + "
\n", + " Note: The expression for the input expression contains single quotes ('text'). The entire string needs to be surrounded by double quotes (\"text\") to preserve the single quotes inside the string. i.e. \"This text has 'single quotes' inside of the double quotes.\"\n", + "
" + ] + }, + { + "cell_type": "markdown", + "id": "1cdfe678-7ee0-41c5-a9e4-c7d770364455", + "metadata": {}, + "source": [ + "Now we plot the filtered image. It should have less noise now." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "12824c23-df07-446a-84e3-67f112ef3b5e", + "metadata": { + "scrolled": true + }, + "outputs": [], + "source": [ + "make_fits_image(filtered_event_list)" + ] + }, + { + "cell_type": "markdown", + "id": "40f244f9-38d2-40df-b599-e68333d20864", + "metadata": {}, + "source": [ + "### 6.4 : Create Light Curve" + ] + }, + { + "cell_type": "markdown", + "id": "691706c2-7106-435a-8921-06263f3b0f41", + "metadata": {}, + "source": [ + "Sometimes, it is necessary to use filters on time in addition to those mentioned above. This is because of soft proton background flaring, which can have count rates of 100 counts/sec or higher across the entire bandpass. It should be noted that the amount of flaring that needs to be removed depends in part on the object observed; a faint, extended object will be more affected than a very bright X-ray source.\n", + "\n", + "To see if background flaring should be removed we plot and examine the light curve." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "d1fe2509-f963-4edd-b6b5-cbf4c2386c80", + "metadata": { + "scrolled": true + }, + "outputs": [], + "source": [ + "light_curve_file='mos1_ltcrv.fits'\n", + "plot_light_curve(filtered_event_list, light_curve_file=light_curve_file)" + ] + }, + { + "cell_type": "markdown", + "id": "5920b928-b0fa-49af-b3ac-c719ffe3a5ca", + "metadata": {}, + "source": [ + "Taking a look at the light curve, we can see that there is a very large flare toward the end of the observation and two much smaller ones in the middle of the exposure. Examining the light curve shows us that during non-flare times, the count rate is quite low, about 1.3 ct/s, with a small increase at 7.3223e7 seconds to about 6 ct/s. We can use that to further filter the data." + ] + }, + { + "cell_type": "markdown", + "id": "fed308c8-af00-413f-be24-6d2d75539628", + "metadata": {}, + "source": [ + "### 6.5 Applying Time or Rate Filters to the Data" + ] + }, + { + "cell_type": "markdown", + "id": "c3f1f7b9-7a3f-4507-ab44-bb22936a4725", + "metadata": {}, + "source": [ + "There are many ways to filter the data. We will demonstrate four different methods. The first three methods will create a Good Time Interval (GTI) file which can then be used as an input to the command `evselect`. This will create a new, filtered, event list.\n", + "\n", + "1. Create a secondary GTI file using the command `tabgtigen` and filter on `RATE`.\n", + "2. Create a secondary GTI file using the command `tabgtigen` and filter on `TIME`.\n", + "3. Create a *new* GTI file using the command `gtibuild` and filter on `TIME`.\n", + "4. Filter on `TIME` using an explicit reference in the inputs to the command `evselect`.\n", + "\n", + "For the last method the user explicitly inputs the time intervals to be used as an expression for the command `evselect` rather than using a separate GTI file. All of these will get the job done, so which to use is a matter of the user's preference." + ] + }, + { + "cell_type": "markdown", + "id": "f82674e1-363b-4d80-856f-d1466db7c507", + "metadata": {}, + "source": [ + "#### 6.5.1 Using `tabgtigen` to filter on `RATE`" + ] + }, + { + "cell_type": "markdown", + "id": "94e20904-1b19-41dc-a863-5d32b5d70de1", + "metadata": {}, + "source": [ + "The inputs for `tabgtigen` are:\n", + "\n", + " table - input file name with count rate table\n", + " gtiset - output file name for selected GTI intervals\n", + " timecolumn - time column\n", + " expression - filtering expression\n", + " \n", + "We choose a rate $<= 6$ counts/s and filter based on that. As the input we use the lightcurve file created in §6.4." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "82ffd9a4-c99e-409d-9dd5-d4596322f448", + "metadata": { + "scrolled": true, + "tags": [] + }, + "outputs": [], + "source": [ + "gti_rate_file = 'gti_rate.fits'\n", + "mos1_filt_rate = 'mos1_filt_rate.fits'\n", + "\n", + "inargs = ['table={0}'.format(light_curve_file), \n", + " 'gtiset={0}'.format(gti_rate_file),\n", + " 'timecolumn=TIME', \n", + " \"expression='(RATE <= 6)'\"]\n", + "\n", + "w('tabgtigen', inargs).run()\n", + "\n", + "inargs = ['table={0}'.format(filtered_event_list),\n", + " 'withfilteredset=yes', \n", + " \"expression='GTI({0},TIME)'\".format(gti_rate_file), \n", + " 'filteredset={0}'.format(mos1_filt_rate),\n", + " 'filtertype=expression', \n", + " 'keepfilteroutput=yes',\n", + " 'updateexposure=yes', \n", + " 'filterexposure=yes']\n", + "\n", + "w('evselect', inargs).run()" + ] + }, + { + "cell_type": "markdown", + "id": "228b63b7-e346-498e-ad63-aa8ad5569652", + "metadata": {}, + "source": [ + "Now we create an image from the new event list that has been filtered based on `RATE`. There should be significantly less noise and only point sources should remain. Compare this final image to the first raw, unfilted image." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "178e497b-216e-4d6f-9017-f9ebc2dee01f", + "metadata": {}, + "outputs": [], + "source": [ + "make_fits_image(mos1_filt_rate, image_file='final_image1.fits')" + ] + }, + { + "cell_type": "markdown", + "id": "79971bfc-33d0-489d-93d2-5a394dee92e7", + "metadata": {}, + "source": [ + "We can also create a new light curve from the filtered event list and compare it to the light curve from §6.4 to see what we have done." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "375f040e-fd4d-4582-a4ee-30c823f295db", + "metadata": {}, + "outputs": [], + "source": [ + "plot_light_curve(mos1_filt_rate)" + ] + }, + { + "cell_type": "markdown", + "id": "c7a99987-a664-43d4-b64c-4ab22844db5d", + "metadata": {}, + "source": [ + "#### 6.5.2 Using `tabgtigen` to filter on `TIME`" + ] + }, + { + "cell_type": "markdown", + "id": "cba81274-4064-47fa-94cb-721a1d551bcb", + "metadata": {}, + "source": [ + "Alternatively, we could have chosen to make a new GTI file by noting the times of the flaring in the light curve and using that as a filtering parameter. The big flare starts around 7.32276e7 s, and the smaller ones are at 7.32119e7 s and 7.32205e7 s. The expression to remove these would be `(TIME <= 73227600)&&!(TIME IN [7.32118e7:7.3212e7])&&!(TIME IN [7.32204e7:7.32206e7])`. The syntax `(TIME <= 73227600)` includes only events with times less than or equal to `73227600`, and the \"!\" symbol stands for the logical \"not\", so use `&&!(TIME in [7.32118e7:7.3212e7])` to exclude events in that time interval. Once the new GTI file is made, we apply it with `evselect`. Everything else remains the same as in §6.5.1." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "d9f9b821-99c5-41dd-ae74-8fb8b8806d14", + "metadata": { + "scrolled": true, + "tags": [] + }, + "outputs": [], + "source": [ + "gti_time_file = 'gti_rate.fits'\n", + "mos1_filt_time = 'mos1_filt_time.fits'\n", + "\n", + "inargs = ['table={0}'.format(light_curve_file), \n", + " 'gtiset={0}'.format(gti_time_file),\n", + " 'timecolumn=TIME', \n", + " \"expression='(TIME <= 73227600)&&!(TIME IN [7.32118e7:7.3212e7])&&!(TIME IN [7.32204e7:7.32206e7])'\"]\n", + "\n", + "w('tabgtigen', inargs).run()\n", + "\n", + "inargs = ['table={0}'.format(filtered_event_list),\n", + " 'withfilteredset=yes', \n", + " \"expression='GTI({0},TIME)'\".format(gti_time_file), \n", + " 'filteredset={0}'.format(mos1_filt_time),\n", + " 'filtertype=expression', \n", + " 'keepfilteroutput=yes',\n", + " 'updateexposure=yes', \n", + " 'filterexposure=yes']\n", + "\n", + "w('evselect', inargs).run()" + ] + }, + { + "cell_type": "markdown", + "id": "6869af46-8601-49d5-8479-45bf33252112", + "metadata": {}, + "source": [ + "We can now plot the image that has been filtered on `TIME` and compare it to the image that was been filtered on `RATE` from §6.5.1." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "4fa94d1d-c4fe-4f4c-be3d-cb5a450cf188", + "metadata": {}, + "outputs": [], + "source": [ + "make_fits_image(mos1_filt_time, image_file='final_image2.fits')\n", + "plot_light_curve(mos1_filt_time)" + ] + }, + { + "cell_type": "markdown", + "id": "3f718ce7-98cd-428f-bf92-7f4102c40536", + "metadata": {}, + "source": [ + "#### 6.5.3 Using `gtibuild` to make a new GTI file and filter on `TIME`" + ] + }, + { + "cell_type": "markdown", + "id": "9cf5f5fa-32fe-4f3d-8c80-b9d8d97cef71", + "metadata": {}, + "source": [ + "This method requires a text file as input. The file should be in ASCII format with eash row on a new line and values for each column separated by spaces. In the first two columns, enter the start and end times (in seconds) that you are interested in, and in the third column, indicate with either a + or - sign whether that region should be kept or removed. Each good (or bad) time interval should get its own line, with any optional comments preceeded by a \"#\". In the example case, we would write in our ASCII file (named gti.txt):" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "ccd4c6b7-d4cd-45c1-a939-a5cfbde2664f", + "metadata": {}, + "outputs": [], + "source": [ + "gti_lines = ['0 73227600 + # Good time from the start of the observation',\n", + " '73211800 73212000 - # But without a small flare here.',\n", + " '73211800 73212000 - # And here.']\n", + "\n", + "with open('gti.txt', 'w') as f:\n", + " f.writelines(gti_lines)" + ] + }, + { + "cell_type": "markdown", + "id": "3509fbf4-c881-4450-9070-3517880411cd", + "metadata": {}, + "source": [ + "We can now run `gtibuild` to create a new GTI file.\n", + "\n", + "---\n", + "The inputs for `gtibuild` are:\n", + "\n", + " file - input text file name\n", + " table - output GTI file name" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "27f7ec6f-6583-4d02-afce-cb17a72e44d7", + "metadata": { + "scrolled": true, + "tags": [] + }, + "outputs": [], + "source": [ + "gti_txt_file = 'gti.txt'\n", + "new_gti_file = 'new_gti.fits'\n", + "mos1_new_gti = 'mos1_new_gti.fits'\n", + "\n", + "inargs = ['file={0}'.format(gti_txt_file),\n", + " 'table={0}'.format(new_gti_file)]\n", + "\n", + "w('gtibuild', inargs).run()" + ] + }, + { + "cell_type": "markdown", + "id": "f8efd67f-d91e-4854-b85a-e9867754b154", + "metadata": {}, + "source": [ + "We can now run `evselect` as before with the new GTI file." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "2e4f40bd-b5bb-4a5c-a8a4-47affacc409b", + "metadata": { + "scrolled": true, + "tags": [] + }, + "outputs": [], + "source": [ + "inargs = ['table={0}'.format(filtered_event_list),\n", + " 'withfilteredset=yes', \n", + " \"expression='GTI({0},TIME)'\".format(new_gti_file), \n", + " 'filteredset={0}'.format(mos1_new_gti),\n", + " 'filtertype=expression', \n", + " 'keepfilteroutput=yes',\n", + " 'updateexposure=yes', \n", + " 'filterexposure=yes']\n", + "\n", + "w('evselect', inargs).run()" + ] + }, + { + "cell_type": "markdown", + "id": "6f16fe45-7f98-4d16-a2fe-f92dfe0e37f2", + "metadata": {}, + "source": [ + "If you want, you can compare the new image and light curve to what was made previously." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "a47fd15c-e483-417e-9e5a-d865a4bb2992", + "metadata": { + "scrolled": true + }, + "outputs": [], + "source": [ + "make_fits_image(mos1_new_gti, image_file='final_image3.fits')\n", + "plot_light_curve(mos1_new_gti)" + ] + }, + { + "cell_type": "markdown", + "id": "de7a04fb-3055-40d8-b4d4-67eccd05d066", + "metadata": {}, + "source": [ + "#### 6.5.4 Filter on `TIME` by Explicit Reference" + ] + }, + { + "cell_type": "markdown", + "id": "342eec0f-b920-4e2c-a7f9-77f0d4eb133e", + "metadata": {}, + "source": [ + "Finally, we could have chosen to forgo making a secondary GTI file altogether, and simply filtered on `TIME` with the standard filtering expression (see §6.3). The filtering expression from §6.3 can be combined with the filtering expression from §6.5.2 and filter the raw data all in one step. In this case, the full filtering expression would be:" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "f8e0529a-9edf-4f60-a5a1-96329d973be0", + "metadata": {}, + "outputs": [], + "source": [ + "expression = \"expression='(PATTERN <= 12)&&(PI in [200:12000])&&#XMMEA_EM&&(TIME <= 73227600) &&!(TIME IN [7.32118e7:7.3212e7])&&!(TIME IN [7.32204e7:7.32206e7])'\"" + ] + }, + { + "cell_type": "markdown", + "id": "a24b4b70-a96b-4faa-a89c-81fde48206ff", + "metadata": {}, + "source": [ + "and we would run `evselect` as the same way we did in §6.3." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "e0f66083-0c1d-4d60-9e27-7f09a293edd0", + "metadata": { + "scrolled": true, + "tags": [] + }, + "outputs": [], + "source": [ + "full_filt_event_list = 'mos1_filt.fits'\n", + "\n", + "inargs = ['table={0}'.format(mos1), \n", + " 'withfilteredset=yes', \n", + " expression, \n", + " 'filteredset={0}'.format(full_filt_event_list), \n", + " 'filtertype=expression', \n", + " 'keepfilteroutput=yes', \n", + " 'updateexposure=yes', \n", + " 'filterexposure=yes']\n", + "\n", + "w('evselect', inargs).run()" + ] + }, + { + "cell_type": "markdown", + "id": "c8c4a032-5247-4a8c-be1d-681f9c82bd85", + "metadata": {}, + "source": [ + "Finally we can compare the result with what we made before." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "0acb96bf-b308-4458-ae4a-7aceddcf3e83", + "metadata": {}, + "outputs": [], + "source": [ + "make_fits_image(full_filt_event_list, image_file='final_image4.fits')\n", + "plot_light_curve(full_filt_event_list)" + ] + }, + { + "cell_type": "markdown", + "id": "a3eb952b-3e62-4622-85f3-c9ed531bc802", + "metadata": {}, + "source": [ + "### Conclusion\n", + "\n", + "We have demonstrated various filtering techniques to remove noise from the raw observation data. Note: How you filter on `RATE` or `TIME` will depend on the light curve of each individual observation. For exceptionally bright sources you may only have to apply the standard filter.\n", + "\n", + "In Part 2 we will cover source detection, spectra extraction, pile up, and preparing the spectra for analysis by creating a redistribution matrix file (RMF) and an ancillary response file (ARF)." + ] + }, + { + "cell_type": "markdown", + "id": "09f0abe8-4b3a-41f0-867f-3f045c9905e0", + "metadata": {}, + "source": [ + "---\n", + "\n", + "Below we have included a short script that incorporates all of the filtering steps for a single observation for MOS1, but without making any plots or image files." + ] + }, + { + "cell_type": "markdown", + "id": "4936faf9-a1b7-4e6a-b610-e3042b2c86f7", + "metadata": {}, + "source": [ + "```python\n", + "obsid = '0123700101'\n", + "odf = pysas.odfcontrol.ODFobject(obsid)\n", + "odf.basic_setup(overwrite=False,repo='heasarc',rerun=False)\n", + "\n", + "os.chdir(odf.work_dir)\n", + "unfiltered_event_list = odf.files['m1evt_list'][0]\n", + "\n", + "# The User can change these file names\n", + "temporary_event_list = 'temporary_event_list.fits' # Created by the \"standard\" filter\n", + "light_curve_file = 'mos1_ltcrv.fits' # Light curve file name\n", + "gti_rate_file = 'gti_rate.fits' # GTI file name\n", + "filtered_event_list = 'filtered_event_list.fits' # Final filtered \n", + "\n", + "# \"Standard\" Filter\n", + "inargs = ['table={0}'.format(unfiltered_event_list), \n", + " 'withfilteredset=yes', \n", + " \"expression='(PATTERN <= 12)&&(PI in [200:4000])&&#XMMEA_EM'\", \n", + " 'filteredset={0}'.format(temporary_event_list), \n", + " 'filtertype=expression', \n", + " 'keepfilteroutput=yes', \n", + " 'updateexposure=yes', \n", + " 'filterexposure=yes']\n", + "\n", + "w('evselect', inargs).run()\n", + "\n", + "# Make Light Curve File\n", + "inargs = ['table={0}'.format(temporary_event_list), \n", + " 'withrateset=yes', \n", + " 'rateset={0}'.format(light_curve_file), \n", + " 'maketimecolumn=yes', \n", + " 'timecolumn=TIME', \n", + " 'timebinsize=100', \n", + " 'makeratecolumn=yes']\n", + "\n", + "w('evselect', inargs).run()\n", + "\n", + "# Make Secondary GTI File\n", + "inargs = ['table={0}'.format(light_curve_file), \n", + " 'gtiset={0}'.format(gti_rate_file),\n", + " 'timecolumn=TIME', \n", + " \"expression='(RATE <= 6)'\"]\n", + "\n", + "w('tabgtigen', inargs).run()\n", + "\n", + "# Filter Using Secondary GTI File\n", + "inargs = ['table={0}'.format(temporary_event_list),\n", + " 'withfilteredset=yes', \n", + " \"expression='GTI({0},TIME)'\".format(gti_rate_file), \n", + " 'filteredset={0}'.format(filtered_event_list),\n", + " 'filtertype=expression', \n", + " 'keepfilteroutput=yes',\n", + " 'updateexposure=yes', \n", + " 'filterexposure=yes']\n", + "\n", + "w('evselect', inargs).run()\n", + "```" + ] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 3 (ipykernel)", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.13.0" + } + }, + "nbformat": 4, + "nbformat_minor": 5 +} diff --git a/documentation/Jupyter_Notebooks/xmm_ABC_guide_images_and_filters.ipynb b/documentation/Jupyter_Notebooks/xmm_ABC_guide_images_and_filters.ipynb index 92b2b7a..539a2f4 100644 --- a/documentation/Jupyter_Notebooks/xmm_ABC_guide_images_and_filters.ipynb +++ b/documentation/Jupyter_Notebooks/xmm_ABC_guide_images_and_filters.ipynb @@ -884,7 +884,7 @@ "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", - "version": "3.13.0" + "version": "3.10.12" } }, "nbformat": 4, diff --git a/obsid/obsid.py b/obsid/obsid.py index 05f0e92..5fa47dd 100644 --- a/obsid/obsid.py +++ b/obsid/obsid.py @@ -46,6 +46,7 @@ from ..sasutils import download_data as dl_data from pysas.logger import get_logger from pysas.sastask import MyTask +from pysas.pysasplot_utils.pysasplot_utils import quick_plot as qp class ObsID: """ @@ -101,7 +102,7 @@ def __init__(self, obsid, # 2. data_dir # 3. cwd if tasklogdir is None: - if os.path.exists(self.data_dir): + if not self.data_dir is None and os.path.exists(self.data_dir): self.tasklogdir = self.data_dir else: # By default get_logger will use cwd @@ -1277,13 +1278,13 @@ def get_SUM_SAS(self,user_defined_file=None): if 'PATH' in line: key, path = line.split() if not os.path.exists(path): - self.logger.error(f'Summary file PATH {path} does not exist. Rerun calibrate_odf with overwrite=True.') - print(f'\nSummary file PATH {path} does not exist. \n\n>>>>Rerun calibrate_odf with overwrite=True.') + self.logger.error(f'Summary file PATH {path} does not exist. Rerun basic_setup with overwrite=True.') + print(f'\nSummary file PATH {path} does not exist. \n\n>>>>Rerun basic_setup with overwrite=True.') exists = False MANIFEST = glob.glob(os.path.join(path, 'MANIFEST*')) - if not os.path.exists(MANIFEST[0]): - self.logger.error(f'Missing {MANIFEST[0]} file in {path}. Missing ODF components? Rerun calibrate_odf with overwrite=True.') - print(f'\nMissing {MANIFEST[0]} file in {path}. Missing ODF components? \n\n>>>>Rerun calibrate_odf with overwrite=True.') + if len(MANIFEST) == 0 or not os.path.exists(MANIFEST[0]): + self.logger.error(f'Missing {MANIFEST[0]} file in {path}. Missing ODF components? Rerun basic_setup with overwrite=True.') + print(f'\nMissing {MANIFEST[0]} file in {path}. Missing ODF components? \n\n>>>>Rerun basic_setup with overwrite=True.') exists = False return exists @@ -1308,6 +1309,49 @@ def clear_work_dir(self): print(f'\n\n{out_note}') shutil.rmtree(self.work_dir) + def quick_eplot(self,fits_event_list_file, + image_file = 'image.fits', + ximagesize = '600', + yimagesize = '600', + vmin = 1.0, + vmax = 10.0, + **kwargs): + """ + Quick plot function for EPIC images. As input takes an + event list and uses 'evselect' to create a FITS image file. + + All standard inputs to 'MyTask' can be passed in as optional + arguments. + """ + + if isinstance(ximagesize, numbers.Number): + ximagesize = str(ximagesize) + if isinstance(yimagesize, numbers.Number): + yimagesize = str(yimagesize) + + inargs = {'table' : f'{fits_event_list_file}', + 'withimageset' : 'yes', + 'imageset' : f'{image_file}', + 'xcolumn' : 'X', + 'ycolumn' : 'Y', + 'imagebinning' : 'imageSize', + 'ximagesize' : f'{ximagesize}', + 'yimagesize' : f'{yimagesize}'} + + # By default this runs silent with no output + MyTask('evselect', inargs, + logfilename = kwargs.get('logfilename', None), + tasklogdir = kwargs.get('tasklogdir', None), + output_to_terminal = kwargs.get('output_to_terminal', False), + output_to_file = kwargs.get('output_to_file', False), + logger = kwargs.get('logger', None)).run() + + ax = qp(image_file,vmin=vmin,vmax=vmax, + save_file = kwargs.get('save_file', False), + out_fname = kwargs.get('out_fname', 'image.png')) + + return ax + def __run_analysis(self, task, inargs, rerun = False, logFile = None): diff --git a/parser.py b/parser.py index 9586eec..ee832a6 100644 --- a/parser.py +++ b/parser.py @@ -137,6 +137,7 @@ def optparser(self): '--verbosity', dest='verbosity', type=int, + nargs=1, default=default_verbosity, choices=range(11), action='store') @@ -188,8 +189,8 @@ def optparser(self): # Apply parse_args method to parser with the options being passed in. # Result is put into parsedargs. The parsedargs object is not a # dictionary but can be shown as such with function vars(). - - self.parsedargs = parser.parse_args(self.argdict['options']) + print([self.argdict['options']]) + self.parsedargs = parser.parse_args([self.argdict['options']]) #print(self.parsedargs) #print(f'vars(self.parsedargs) = \n{vars(self.parsedargs)}') @@ -331,9 +332,12 @@ def procopt(self): warning = self.parsedargs.warning # verbosity if self.parsedargs.verbosity: - os.environ['SAS_VERBOSITY'] = str(self.parsedargs.verbosity) + verbo = self.parsedargs.verbosity + if type(verbo) is list: + verbo = verbo[0] + os.environ['SAS_VERBOSITY'] = str(verbo) if str(os.environ.get('SAS_VERBOSITY')) != '4': - print('SAS_VERBOSITY = {}'.format(str(os.environ.get('SAS_VERBOSITY')))) + self.logger.info('SAS_VERBOSITY = {}'.format(str(os.environ.get('SAS_VERBOSITY')))) return Exit diff --git a/pysasplot_utils/pysasplot_utils.py b/pysasplot_utils/pysasplot_utils.py index 1666209..36b5bdd 100644 --- a/pysasplot_utils/pysasplot_utils.py +++ b/pysasplot_utils/pysasplot_utils.py @@ -18,22 +18,19 @@ # pysasplot_utils.py from .version import VERSION -from pysas import SAS_RELEASE, SAS_AKA - -__version__ = f'pysasplot_utils (pysasplot_utils-{VERSION}) [{SAS_RELEASE}-{SAS_AKA}]' +#from pysas import SAS_RELEASE, SAS_AKA +#__version__ = f'pysasplot_utils (pysasplot_utils-{VERSION}) [{SAS_RELEASE}-{SAS_AKA}]' +__version__ = f'pysasplot_utils (pysasplot_utils-{VERSION})' +import os, numbers, sys, re, warnings, pickle import pysas.pyutils.pyutils as pyutils from astropy.io import fits +from astropy.wcs import WCS import matplotlib.pyplot as plt -import numpy as np -import os from astropy.table import Table -import sys -import re -import warnings +import numpy as np import matplotlib.backends.backend_pdf -import pickle from pypdf import PdfMerger from matplotlib.patches import Rectangle from matplotlib.collections import PatchCollection @@ -108,6 +105,30 @@ def plot_spectra_model(spectrum,plot_file_name='spectra_model_plot.png'): return fig, ax0, ax1 +def quick_plot(image_file, + vmin = 1.0, + vmax = 1e2, + save_file = False, + out_fname = 'image.png'): + """ + Displays a FITS image file. Returns the axis handle. + """ + hdu = fits.open(image_file)[0] + wcs = WCS(hdu.header) + + ax = plt.subplot(projection=wcs) + plt.imshow(hdu.data, origin='lower', norm='log', vmin=vmin, vmax=vmax) + ax.set_facecolor("black") + plt.grid(color='blue', ls='solid') + plt.xlabel('RA') + plt.ylabel('Dec') + plt.colorbar() + plt.show() + if save_file: + plt.savefig(out_fname) + + return ax + def text_plot(fits_file, extra_text = ''): """ Prepares the text for the plot reading Keywords from the given FITS file. diff --git a/pyutils/pyutils.py b/pyutils/pyutils.py index 0baad1b..2584ff8 100644 --- a/pyutils/pyutils.py +++ b/pyutils/pyutils.py @@ -18,10 +18,10 @@ # pyutils.py from .version import VERSION -from pysas import SAS_RELEASE, SAS_AKA - -__version__ = f'pyutils (pyutils-{VERSION}) [{SAS_RELEASE}-{SAS_AKA}]' +#from pysas import SAS_RELEASE, SAS_AKA +#__version__ = f'pyutils (pyutils-{VERSION}) [{SAS_RELEASE}-{SAS_AKA}]' +__version__ = f'pyutils (pyutils-{VERSION})' import numpy as np import subprocess diff --git a/sastask.py b/sastask.py index d959521..3a68fd2 100644 --- a/sastask.py +++ b/sastask.py @@ -234,17 +234,20 @@ def readparfile(self): self.rev_mandpar_string_dict = t.rev_mandpar_string_dict def processargs(self): - p = ParseArgs(self.taskname, self.inargs, logger = self.logger) - p.optparser() - - # Execute options which require immediate action - # Options which are for environment (which are cumulative) - # do not change default False value of Exit. - self.Exit = p.procopt() - if self.Exit: - return self.Exit - - # Remove the options from inargs + # Only if options are passed in + self.Exit = False + if len(self.inargs['options']) > 0: + p = ParseArgs(self.taskname, self.inargs, logger = self.logger) + p.optparser() + + # Execute options which require immediate action + # Options which are for environment (which are cumulative) + # do not change default False value of Exit. + self.Exit = p.procopt() + if self.Exit: + return self.Exit + + # Remove the options from argsdic self.argsdic = self.inargs self.argsdic.pop('options') @@ -410,8 +413,9 @@ def run(self): cmd += "' " else: cmd += k + '=' + v + ' ' - - print(f'Executing: \n{cmd}') + + if self.output_to_terminal: + print(f'Executing: \n{cmd}') try: logger = get_logger(self.taskname, From 83e019fe5418f7d9e7b83eddaec9a7521e0b1d3b Mon Sep 17 00:00:00 2001 From: rjtanner Date: Thu, 17 Jul 2025 21:27:52 -0400 Subject: [PATCH 11/17] Fix bug in parser --- parser.py | 119 ++++++++++++++++++++++++++++++++--------------------- sastask.py | 46 ++++++++++++--------- 2 files changed, 99 insertions(+), 66 deletions(-) diff --git a/parser.py b/parser.py index ee832a6..a96a2c1 100644 --- a/parser.py +++ b/parser.py @@ -36,8 +36,6 @@ Method procopt either executes the immediate options or sets the environment variables that modify the execution of the task. - -Task parameters entered are returned in list tparams. """ @@ -189,39 +187,31 @@ def optparser(self): # Apply parse_args method to parser with the options being passed in. # Result is put into parsedargs. The parsedargs object is not a # dictionary but can be shown as such with function vars(). - print([self.argdict['options']]) + self.parsedargs = parser.parse_args([self.argdict['options']]) #print(self.parsedargs) #print(f'vars(self.parsedargs) = \n{vars(self.parsedargs)}') #print(f'self.parsedargs.pvpairs = {self.parsedargs.pvpairs}') - - # Put into list tparams parameters entered in the command line - # as pairs param=value - params = list(self.argdict.keys()) - self.tparams = params.remove('options') - # Depending on the options entered, performs actions - def procopt(self): + def exe_options(self): """ - Method to execute options or parameters that require immediate action. - - There are two sets of otions/parameters that require immediate action: - - 1. Options that execute the command and exit. These are: - version(--version, -v), help(--help, -h), param(--param, -p), - dialog(--dialog, -d) and manpage(--manpage, -m). - - 2. Options that set environment variables and then continue running - the SAS task. These are: - -V/--verbosity (SAS_VERBOSITY), -c/--noclobber, - (SAS_CLOBBER), -a/--ccfpath (SAS_CCFPATH), - -i/--ccf (SAS_CCF), -o/--odf (SAS_ODF), -f/--ccffiles, - -w/--warning, -t/--trace. - - Returns 'Exit' which if True will send the exit command up the chain. - If False, then pySAS will continue to execute. + Method to execute options or parameters that + require immediate action. + + These include options that execute the command + and exit. These are: + + version(--version, -v) + help(--help, -h) + param(--param, -p) + dialog(--dialog, -d) + manpage(--manpage, -m) + + Returns 'Exit' which if True will send the exit + command up the chain. If False, then pySAS will + continue to execute. """ # Exit is set to False @@ -302,44 +292,81 @@ def procopt(self): if Exit: return Exit + def env_options(self): + """ + Method to execute options or parameters that + set environment variables and then continue running + the SAS task. These are: + + -V/--verbosity (SAS_VERBOSITY) + -c/--noclobber (SAS_CLOBBER) + -a/--ccfpath (SAS_CCFPATH) + -i/--ccf (SAS_CCF) + -o/--odf (SAS_ODF) + -f/--ccffiles + -w/--warning + -t/--trace + + Depending on the action, previously set values + will be returned. + """ + # return_params is a dictionary to hold the + # previously set values. + return_params = {} + env_options_list = [] # # Excluding warning, which I do not know how to handle yet, - # the next five options are accumulative, if they are present they change - # environment variables. + # the next five options are accumulative, if they are + # present they change environment variables. # They do not return control to caller. # # sas_ccfpath if self.parsedargs.sas_ccfpath: - print('SAS_CCFPATH = {}'.format(str(self.parsedargs.sas_ccfpath[0]))) - os.environ['SAS_CCFPATH'] = str(self.parsedargs.sas_ccfpath[0]) + return_params['SAS_CCFPATH'] = os.environ.get('SAS_CCFPATH') + envar_val = str(self.parsedargs.sas_ccfpath[0]) + env_options_list.append(f'-a {envar_val}') + self.logger.info(f'SAS_CCFPATH = {envar_val}') + #os.environ['SAS_CCFPATH'] = envar_val # noclobber if self.parsedargs.noclobber: - os.environ['SAS_CLOBBER'] = '0' - print('SAS_CLOBBER = {}'.format(str(os.environ.get('SAS_CLOBBER')))) + return_params['SAS_CLOBBER'] = os.environ.get('SAS_CLOBBER') + envar_val = '0' + env_options_list.append('-c') + self.logger.info(f'SAS_CLOBBER = {envar_val}') + #os.environ['SAS_CLOBBER'] = envar_val # sas_ccf if self.parsedargs.sas_ccf: - print('SAS_CCF = {}'.format(str(self.parsedargs.sas_ccf[0]))) - os.environ['SAS_CCF'] = str(self.parsedargs.sas_ccf[0]) + return_params['SAS_CCF'] = os.environ.get('SAS_CCF') + envar_val = str(self.parsedargs.sas_ccf[0]) + env_options_list.append(f'-i {envar_val}') + self.logger.info(f'SAS_CCF = {envar_val}') + #os.environ['SAS_CCF'] = envar_val # sas_odf if self.parsedargs.sas_odf: - print('SAS_ODF = {}'.format(str(self.parsedargs.sas_odf[0]))) - os.environ['SAS_ODF'] = str(self.parsedargs.sas_odf[0]) + return_params['SAS_ODF'] = os.environ.get('SAS_ODF') + envar_val = str(self.parsedargs.sas_odf[0]) + env_options_list.append(f'-o {envar_val}') + self.logger.info(f'SAS_ODF = {envar_val}') + #os.environ['SAS_ODF'] = envar_val # ccffiles if self.parsedargs.ccffiles: - print('CCF files = {}'.format(str(self.parsedargs.ccffiles[0]))) + envar_val = str(self.parsedargs.sas_odf[0]) + env_options_list.append(f'-f {envar_val}') + self.logger.info(f'CCF files = {envar_val}') # warning if self.parsedargs.warning: warning = self.parsedargs.warning # verbosity if self.parsedargs.verbosity: - verbo = self.parsedargs.verbosity - if type(verbo) is list: - verbo = verbo[0] - os.environ['SAS_VERBOSITY'] = str(verbo) - if str(os.environ.get('SAS_VERBOSITY')) != '4': - self.logger.info('SAS_VERBOSITY = {}'.format(str(os.environ.get('SAS_VERBOSITY')))) - - return Exit + return_params['SAS_VERBOSITY'] = os.environ.get('SAS_VERBOSITY') + envar_val = str(self.parsedargs.verbosity[0]) + env_options_list.append(f'-V {envar_val}') + self.logger.info(f'SAS_VERBOSITY = {envar_val}') + #os.environ['SAS_VERBOSITY'] = envar_val + + return_params['env_options'] = " ".join(env_options_list) + + return return_params def __repr__(self): return f'{self.__class__.__name__}({self.taskname} - {self.argdict})' diff --git a/sastask.py b/sastask.py index 3a68fd2..9f61aa7 100644 --- a/sastask.py +++ b/sastask.py @@ -237,18 +237,19 @@ def processargs(self): # Only if options are passed in self.Exit = False if len(self.inargs['options']) > 0: - p = ParseArgs(self.taskname, self.inargs, logger = self.logger) - p.optparser() + pararg = ParseArgs(self.taskname, self.inargs, logger = self.logger) + pararg.optparser() # Execute options which require immediate action - # Options which are for environment (which are cumulative) - # do not change default False value of Exit. - self.Exit = p.procopt() + self.Exit = pararg.exe_options() if self.Exit: return self.Exit + + # Deal with options that set environment variables + env_opts = pararg.env_options() # Remove the options from argsdic - self.argsdic = self.inargs + self.argsdic = dict(self.inargs) self.argsdic.pop('options') # 1st check: Whether or not parameters in inargs are defined in the parameter file @@ -320,11 +321,6 @@ def processargs(self): # in the command line, let us produce now a single object with all # parameters which we can pass to the module to run. - # argsdic is a dictionary with the pairs param, value - # as entered from the command line from 'param=value' - - argsdic = self.inargs - # Load defaults with all parameters default values. # Use dictionary method 'setdefault' to set the value for a given key; # here the key is 'default'. @@ -348,6 +344,10 @@ def processargs(self): #print(k, a, defaults[k]) break + # Return options that modify the environment to argdic + if len(self.inargs['options']) > 0: + self.argsdic['options'] = env_opts['env_options'] + # Merge self.argsdic onto parsdic. Those values set in command line, # from self.argsdic, will overwrite the defaults obtained from the par file, # from parsdic. The resulting dictionary, self.iparsdic, is what we will @@ -391,10 +391,13 @@ def run(self): m.run(self.iparsdic) else: - cmd = '' - cmd += self.taskname + ' ' - for parval in self.iparsdic.items(): - k, v = parval + # Build a list of parameters based on iparsdic + cmd_list = [] + cmd_list.append(self.taskname) + for k, v in self.iparsdic.items(): + if k == 'options': + cmd_list.append(v) + continue #Remove single quotes a double quotes from the python input parameters #SOC-SPR-7684 if v.startswith("\"") or v.endswith("\""): @@ -403,17 +406,20 @@ def run(self): v = v.replace('\'','') if ' ' or '|' in v: - cmd += k + '=' + "'" + singparam = k + '=' + "'" vc = v.split(' ') for i in range(len(vc)): if i == len(vc) - 1: - cmd += vc[i] + singparam += vc[i] else: - cmd += vc[i] + ' ' - cmd += "' " + singparam += vc[i] + ' ' + singparam += "'" + cmd_list.append(singparam) else: - cmd += k + '=' + v + ' ' + cmd_list.append(k + '=' + v) + # Join all the parameters into a single command + cmd = " ".join(cmd_list) if self.output_to_terminal: print(f'Executing: \n{cmd}') From 6b85754e9c38db874ce4bbc34f464464c731bcbe Mon Sep 17 00:00:00 2001 From: rjtanner Date: Thu, 17 Jul 2025 21:50:02 -0400 Subject: [PATCH 12/17] Add quick_light_curve_plot --- obsid/obsid.py | 47 +++++++++++++++++++++++++++--- pysasplot_utils/pysasplot_utils.py | 26 +++++++++++++---- 2 files changed, 64 insertions(+), 9 deletions(-) diff --git a/obsid/obsid.py b/obsid/obsid.py index 5fa47dd..3ed7d05 100644 --- a/obsid/obsid.py +++ b/obsid/obsid.py @@ -46,7 +46,8 @@ from ..sasutils import download_data as dl_data from pysas.logger import get_logger from pysas.sastask import MyTask -from pysas.pysasplot_utils.pysasplot_utils import quick_plot as qp +from pysas.pysasplot_utils.pysasplot_utils import quick_image_plot as qip +from pysas.pysasplot_utils.pysasplot_utils import quick_light_curve_plot as qlcp class ObsID: """ @@ -1346,12 +1347,50 @@ def quick_eplot(self,fits_event_list_file, output_to_file = kwargs.get('output_to_file', False), logger = kwargs.get('logger', None)).run() - ax = qp(image_file,vmin=vmin,vmax=vmax, - save_file = kwargs.get('save_file', False), - out_fname = kwargs.get('out_fname', 'image.png')) + ax = qip(image_file,vmin=vmin,vmax=vmax, + save_file = kwargs.get('save_file', False), + out_fname = kwargs.get('out_fname', 'image.png')) return ax + def quick_lcplot(self,fits_event_list_file, + light_curve_file = 'light_curve.fits', + timebinsize = '100', + **kwargs): + """ + Quick plot function to generate a light curve. As input takes an + event list and uses 'evselect' to create a FITS image file. + + All standard inputs to 'MyTask' can be passed in as optional + arguments. + """ + + if isinstance(timebinsize, numbers.Number): + timebinsize = str(timebinsize) + + inargs = {'table' : f'{fits_event_list_file}', + 'withrateset' : 'yes', + 'rateset' : f'{light_curve_file}', + 'maketimecolumn' : 'yes', + 'timecolumn' : 'TIME', + 'imagebinning' : 'imageSize', + 'timebinsize' : f'{timebinsize}', + 'makeratecolumn' : 'yes'} + + # By default this runs silent with no output + MyTask('evselect', inargs, + logfilename = kwargs.get('logfilename', None), + tasklogdir = kwargs.get('tasklogdir', None), + output_to_terminal = kwargs.get('output_to_terminal', False), + output_to_file = kwargs.get('output_to_file', False), + logger = kwargs.get('logger', None)).run() + + plt = qlcp(light_curve_file, + save_file = kwargs.get('save_file', False), + out_fname = kwargs.get('out_fname', 'light_curve.png')) + + return plt + def __run_analysis(self, task, inargs, rerun = False, logFile = None): diff --git a/pysasplot_utils/pysasplot_utils.py b/pysasplot_utils/pysasplot_utils.py index 36b5bdd..d29a387 100644 --- a/pysasplot_utils/pysasplot_utils.py +++ b/pysasplot_utils/pysasplot_utils.py @@ -105,11 +105,11 @@ def plot_spectra_model(spectrum,plot_file_name='spectra_model_plot.png'): return fig, ax0, ax1 -def quick_plot(image_file, - vmin = 1.0, - vmax = 1e2, - save_file = False, - out_fname = 'image.png'): +def quick_image_plot(image_file, + vmin = 1.0, + vmax = 1e2, + save_file = False, + out_fname = 'image.png'): """ Displays a FITS image file. Returns the axis handle. """ @@ -129,6 +129,22 @@ def quick_plot(image_file, return ax +def quick_light_curve_plot(light_curve_file, + save_file = False, + out_fname = 'light_curve.png'): + """ + Plots a light curve from a light curve FITS file. + """ + ts = Table.read(light_curve_file,hdu=1) + plt.plot(ts['TIME'],ts['RATE']) + plt.xlabel('Time (s)') + plt.ylabel('Count Rate (ct/s)') + plt.show() + if save_file: + plt.savefig(out_fname) + + return plt + def text_plot(fits_file, extra_text = ''): """ Prepares the text for the plot reading Keywords from the given FITS file. From 073b0d1959b9c1458780bb1c29e38a79db0a7997 Mon Sep 17 00:00:00 2001 From: rjtanner Date: Thu, 17 Jul 2025 22:12:40 -0400 Subject: [PATCH 13/17] Quality update --- obsid/obsid.py | 8 ++++---- pysasplot_utils/pysasplot_utils.py | 16 ---------------- 2 files changed, 4 insertions(+), 20 deletions(-) diff --git a/obsid/obsid.py b/obsid/obsid.py index 3ed7d05..1766191 100644 --- a/obsid/obsid.py +++ b/obsid/obsid.py @@ -1385,11 +1385,11 @@ def quick_lcplot(self,fits_event_list_file, output_to_file = kwargs.get('output_to_file', False), logger = kwargs.get('logger', None)).run() - plt = qlcp(light_curve_file, - save_file = kwargs.get('save_file', False), - out_fname = kwargs.get('out_fname', 'light_curve.png')) + qlcp(light_curve_file, + save_file = kwargs.get('save_file', False), + out_fname = kwargs.get('out_fname', 'light_curve.png')) - return plt + return def __run_analysis(self, task, inargs, rerun = False, diff --git a/pysasplot_utils/pysasplot_utils.py b/pysasplot_utils/pysasplot_utils.py index d29a387..65b78de 100644 --- a/pysasplot_utils/pysasplot_utils.py +++ b/pysasplot_utils/pysasplot_utils.py @@ -143,8 +143,6 @@ def quick_light_curve_plot(light_curve_file, if save_file: plt.savefig(out_fname) - return plt - def text_plot(fits_file, extra_text = ''): """ Prepares the text for the plot reading Keywords from the given FITS file. @@ -170,7 +168,6 @@ def text_plot(fits_file, extra_text = ''): return text_plot - def ingest_data(fits_file, in_data, label = 'label'): """ Prepares the data from the input in a key-value, ready to plot with the @@ -241,7 +238,6 @@ def ingest_data(fits_file, in_data, label = 'label'): return data - def is_iterable(py_obj): """ Given a Python object, will return True or False if it's and iterable object aside @@ -261,7 +257,6 @@ def is_iterable(py_obj): else: return False - def get_time_deltas(fits_file, extension = 1, points = 512, x_data = 'TIME', card = 'TIMEDEL'): """ Finds the proper Delta intervals for a FITS file. @@ -316,7 +311,6 @@ def get_time_deltas(fits_file, extension = 1, points = 512, x_data = 'TIME', car return DTin, DTout - def TSrebin(tstable, DTin, DTout, t_xlabel = 'TIME', t_ylabel = 'RATE', t_elabel = 'ERROR', fracexp = 'FRACEXP'): """ Re-binning function. @@ -406,7 +400,6 @@ def TSrebin(tstable, DTin, DTout, t_xlabel = 'TIME', t_ylabel = 'RATE', t_elabel return ntstable - def load_figures(list_of_saved_figs): """ Loads a list of pickled figures (passed as a list of paths) and returns a list of figure objects. @@ -431,7 +424,6 @@ def load_figures(list_of_saved_figs): return saved_figs - def saves_in_pdf(fig_list, output_name = 'output', papertype = 'a4'): """ Saves the given figures into a single pdf file. @@ -473,7 +465,6 @@ def saves_in_pdf(fig_list, output_name = 'output', papertype = 'a4'): return os.path.abspath('{}'.format(output_name)) - def simple_1d_hist(y_data, x_label = 'x', y_label = 'y', add_text = '', scale = '', nbins = 20, sharebins = False, \ fits_file = '', fits_info = True, plot_title = '', outformat = 'pdf'): """ @@ -573,7 +564,6 @@ def simple_1d_hist(y_data, x_label = 'x', y_label = 'y', add_text = '', scale = return fig - def simple_2d_plot(x_data, y_data, x_data_errors = '', y_data_errors = '', plot_title = '', x_label = 'x', y_label = 'y', fits_file = '', fits_info = True, \ add_text = '', scale = '', points = 512, outformat = 'png'): """ @@ -707,7 +697,6 @@ def simple_2d_plot(x_data, y_data, x_data_errors = '', y_data_errors = '', plot_ return fig - def ingest_table(table, points, x_label, y_labels, x_error_label = None, y_errors_label = None): """ Ingest the data from a given table and returns the data using Python @@ -770,7 +759,6 @@ def ingest_table(table, points, x_label, y_labels, x_error_label = None, y_error return(x_data, y_data, x_error, y_error) - def merge_pdf(pdf_files, output_file): """ Merges several PDF files passed as the arguments. @@ -807,7 +795,6 @@ def merge_pdf(pdf_files, output_file): return 1 - def plot_image(path_to_image, ext = 0, output = None): """ Plots and saves an image corresponding to a FITS image. @@ -837,7 +824,6 @@ def plot_image(path_to_image, ext = 0, output = None): return 0 - def check_format_compatibility(out_format): """ Checks if the input format is available as a matplotlib backend format. @@ -856,7 +842,6 @@ def check_format_compatibility(out_format): else: return False - def plot_region_box(ax, x1, y1, width, height, angle = 0, fill = False, colour = 'green', text = None, transform = None): ''' Returns an axis object with with a box region printed on it. @@ -891,7 +876,6 @@ def plot_region_box(ax, x1, y1, width, height, angle = 0, fill = False, colour = return None - def reg_to_list(reg): ''' Gets the information from a region based on the input string (based on ds9 formatting). From 95f86141db15fa77fc40f5573c5800c47d03fcde Mon Sep 17 00:00:00 2001 From: rjtanner Date: Fri, 18 Jul 2025 15:09:55 -0400 Subject: [PATCH 14/17] Modification to how env options are handled --- ChangeLog | 45 +++++++++++++++++++++++++++------ logger.py | 13 +++++----- parser.py | 50 ++++++++++++++++++++----------------- sastask.py | 73 +++++++++++++++++++++++++++++++++++++++++++++++++----- 4 files changed, 138 insertions(+), 43 deletions(-) diff --git a/ChangeLog b/ChangeLog index e4124c3..ae6a10c 100644 --- a/ChangeLog +++ b/ChangeLog @@ -9,18 +9,44 @@ Version 2.0 - 2025-??-?? (RT) importlib.resources. - runtask.py: File has been removed and all functionality has been transferred to - sastask.py. It only added an extra layer to the process. + sastask.py. It only added an extra layer to the process. + sastask.py: The class SASTask has been deprecated since it was only an abstract class, - with only abstract methods and a single child, MyTask. MyTask was the only - class used in the rest of the code. To simplify things, MyTask has been - made the only useful class, but SASTask is declared as a child of MyTask + with only abstract methods and a single child, MyTask. MyTask was the only + class used in the rest of the code. To simplify things, MyTask has been + made the only useful class, but SASTask is declared as a child of MyTask for legacy purposes, until all references to it can be removed. - Functionality from runtask has been placed in the 'run' method in MyTask. + Functionality from runtask has been placed in the 'run' method in MyTask. The method 'runtask' has been kept as a place holder for legacy code. It just calls 'run'. + Changed how options that affect environment variables are handled. For + Python based SAS tasks, pySAS will *temporarily* change the environment + variables, run the task, and then restore the environment variables to + their previous setting. For non-Python based SAS tasks, these options are + passed to the subprocess command to run the task. + + Options that will execute and exit are: + -v (version) + -h (help) + -p (param) + -d (dialog) + -m (manpage) + + For **only** Python based tasks: + Options that will *temporarily* set environment variables are: + -V (SAS_VERBOSITY) + -a (SAS_CCFPATH) + -i (SAS_CCF) + -o (SAS_ODF) + + Options that are not handled for Python based SAS tasks (but are + passed to the task in 'iparsdic', so in principle they can be used.) + -f/--ccffiles + -w/--warning + -t/--trace + - wrapper.py: The Wrapper class has been deprecated since its only function was to create a MyTask object. It has been left in place until legacy code can be switched over to MyTask. @@ -31,14 +57,14 @@ Version 2.0 - 2025-??-?? (RT) 'get_logger' function, but through the MyTask object which accepts all necessary inputs. - The user can declare a directory for the log files, or even a single log file + The user can declare a directory for the log files, or even a single log file for all output from all SAS tasks called. + version.py: At the top level version.py only contains the version information for pySAS. For independent tasks they maintain their own version numbers, but for all other subdirectories they all point to the master pySAS version file. - get_sas_version dedicated function to run 'sasversion' and get SAS version + get_sas_version dedicated function to run 'sasversion' and get SAS version information. + */version.py: All version files for individual SAS tasks now only contain their version @@ -60,7 +86,10 @@ Version 2.0 - 2025-??-?? (RT) Significant changes to pySAS. New class: ObsID + parser.py : Update documentation, add logger to ParseArgs, changed 'taskparser' to - 'optparser'. + 'optparser'. 'procopt' has been split into 'exe_options' and + 'env_options' to handle options that require immediate action + (exe_options), and options that handle environment variables + (env_options). + param.py : Update documentation, add logger to paramXmlInfoReader. diff --git a/logger.py b/logger.py index 0e46647..e551e75 100644 --- a/logger.py +++ b/logger.py @@ -57,11 +57,11 @@ def get_logger(taskname: str, of "{taskname}.log". Useful for putting all output from multiple tasks into the same file. - tasklogdir : (default: cwd) Directory where to write the log - file. - Priority of defaults for task_logdir - 1. tasklogdir (passed in to function) - 2. SAS_TASKLOGDIR (envirnment variable) - 3. cwd (final default) + file. + Priority of defaults for task_logdir + 1. tasklogdir (passed in to function) + 2. SAS_TASKLOGDIR (envirnment variable) + 3. cwd (final default) - pylogger : True: Use logger settings for Python logging False: Use logger settings for subprocess logging Only set to 'False' in sastask.py -> MyTask.run() @@ -100,7 +100,8 @@ def get_logger(taskname: str, if pylogger: # For Python based logging # Set verbosity - verbosity = int(os.getenv('SAS_VERBOSITY')) + if verbosity is None: + verbosity = int(os.getenv('SAS_VERBOSITY')) match(verbosity): case 1: level = "CRITICAL" diff --git a/parser.py b/parser.py index a96a2c1..15e7d27 100644 --- a/parser.py +++ b/parser.py @@ -310,63 +310,67 @@ def env_options(self): Depending on the action, previously set values will be returned. """ - # return_params is a dictionary to hold the - # previously set values. - return_params = {} + # return_options is a dictionary to hold set options + return_options = {} env_options_list = [] - # - # Excluding warning, which I do not know how to handle yet, - # the next five options are accumulative, if they are - # present they change environment variables. - # They do not return control to caller. - # + + # The options are accumulative, if they are + # present they are collected into a list and + # returned to MyTask. + # sas_ccfpath if self.parsedargs.sas_ccfpath: - return_params['SAS_CCFPATH'] = os.environ.get('SAS_CCFPATH') envar_val = str(self.parsedargs.sas_ccfpath[0]) env_options_list.append(f'-a {envar_val}') + return_options['SAS_CCFPATH'] = envar_val self.logger.info(f'SAS_CCFPATH = {envar_val}') - #os.environ['SAS_CCFPATH'] = envar_val # noclobber if self.parsedargs.noclobber: - return_params['SAS_CLOBBER'] = os.environ.get('SAS_CLOBBER') - envar_val = '0' + envar_val = False env_options_list.append('-c') + return_options['SAS_CLOBBER'] = envar_val self.logger.info(f'SAS_CLOBBER = {envar_val}') - #os.environ['SAS_CLOBBER'] = envar_val # sas_ccf if self.parsedargs.sas_ccf: - return_params['SAS_CCF'] = os.environ.get('SAS_CCF') envar_val = str(self.parsedargs.sas_ccf[0]) env_options_list.append(f'-i {envar_val}') + return_options['SAS_CCF'] = envar_val self.logger.info(f'SAS_CCF = {envar_val}') - #os.environ['SAS_CCF'] = envar_val # sas_odf if self.parsedargs.sas_odf: - return_params['SAS_ODF'] = os.environ.get('SAS_ODF') envar_val = str(self.parsedargs.sas_odf[0]) env_options_list.append(f'-o {envar_val}') + return_options['SAS_ODF'] = envar_val self.logger.info(f'SAS_ODF = {envar_val}') - #os.environ['SAS_ODF'] = envar_val # ccffiles if self.parsedargs.ccffiles: envar_val = str(self.parsedargs.sas_odf[0]) env_options_list.append(f'-f {envar_val}') + return_options['CCF_files'] = envar_val self.logger.info(f'CCF files = {envar_val}') # warning if self.parsedargs.warning: - warning = self.parsedargs.warning + envar_val = str(self.parsedargs.warning[0]) + env_options_list.append(f'-w {envar_val}') + return_options['WARNING'] = envar_val + self.logger.info(f'WARNING = {envar_val}') + # trace + if self.parsedargs.trace: + envar_val = True + env_options_list.append('-t') + return_options['TRACE'] = envar_val + self.logger.info(f'Trace = {envar_val}') # verbosity if self.parsedargs.verbosity: - return_params['SAS_VERBOSITY'] = os.environ.get('SAS_VERBOSITY') envar_val = str(self.parsedargs.verbosity[0]) env_options_list.append(f'-V {envar_val}') + return_options['SAS_VERBOSITY'] = envar_val self.logger.info(f'SAS_VERBOSITY = {envar_val}') - #os.environ['SAS_VERBOSITY'] = envar_val - return_params['env_options'] = " ".join(env_options_list) + # Add the list of all options to return_options + return_options['env_options'] = " ".join(env_options_list) - return return_params + return return_options def __repr__(self): return f'{self.__class__.__name__}({self.taskname} - {self.argdict})' diff --git a/sastask.py b/sastask.py index 9f61aa7..dcc8c4f 100644 --- a/sastask.py +++ b/sastask.py @@ -223,6 +223,19 @@ def __repr__(self): return f'{self.__class__.__name__}({self.taskname}, {self.inargs})' def readparfile(self): + """ + Reads the parameter file (taskname.par) for the task. Returns + various lists and dictionaries. + - allparams : Dictionary { parameter: {attributes} } + - mandpar : List of all mandatory parameters/subparameters + - mainparams: List of main paramaters + - parmap : Dictionary { pname: [ subparameters ...], ...} + - mandpar_dict: Dictionary, key = mandatory subparamater, value=its parent parameter + - rev_mandpar_dict: Dictionary, keys = parent paramater, + value = list of all mandatory subparameters + - rev_mandpar_string_dict: Dictionary, keys = parent parameter type 'string' + value = list of alternatives + """ t = paramXmlInfoReader(self.taskname, logger = self.logger) t.xmlParser() self.allparams = t.allparams @@ -246,6 +259,10 @@ def processargs(self): return self.Exit # Deal with options that set environment variables + # For non-Python based tasks these will be passed in + # as part of the command for the subprocess call. + # For Python based tasks, they will have to be handled + # in the .run() function. env_opts = pararg.env_options() # Remove the options from argsdic @@ -282,7 +299,7 @@ def processargs(self): newinarg = k + '=' + alt self.argsdic[k] = alt if k in self.argsdic.keys(): - print(f'Warning: No need to include {k}. Assumed {newinarg}') + self.logger.warning(f'No need to include {k}. Assumed {newinarg}') break elif p in v and k not in self.argsdic.keys(): raise Exception(f'Mandatory sub-parameter {p} requires {k} be present') @@ -345,8 +362,13 @@ def processargs(self): break # Return options that modify the environment to argdic + self.env_options = {} if len(self.inargs['options']) > 0: - self.argsdic['options'] = env_opts['env_options'] + for k, v in env_opts.items(): + if k == 'env_options': + self.argsdic['options'] = env_opts['env_options'] + else: + self.env_options[k] = v # Merge self.argsdic onto parsdic. Those values set in command line, # from self.argsdic, will overwrite the defaults obtained from the par file, @@ -369,9 +391,13 @@ def run(self): If taskname is not a Python SAS task, there will not be a run function, so we will invoke subprocess """ + self.logger.debug(f'Running {self.taskname}') + self.logger.debug(f'Reading parameter file.') self.readparfile() + self.logger.debug(f'Processing input arguments') self.processargs() if self.Exit: + self.logger.debug(f'Exit called by processargs') return self.Exit sas_path = os.environ.get('SAS_PATH') @@ -384,14 +410,51 @@ def run(self): for line in (my_resources / "pysaspkgs").read_text().splitlines(): pysaspkgs.append(line) + # For Python based SAS tasks if self.taskname in pysaspkgs: - + self.logger.debug(f'Using Python based SAS task: {self.taskname}') + # Add the environment options to iparsdic + self.logger.debug(f'Adding environment options to iparsdic') + self.iparsdic['options'] = dict(self.env_options) + temp_dict = {} + for k, v in self.env_options.items(): + match(k): + case 'SAS_CCFPATH' | 'SAS_CCF' | 'SAS_ODF' | 'SAS_VERBOSITY': + temp_dict[k] = os.getenv(k) + self.logger.debug(f'Storing previous setting of {k}={temp_dict[k]}') + os.environ[k] = v + self.logger.debug(f'Temporarely changing {k} to {v}') + case 'SAS_CLOBBER' | 'CCF_files' | 'WARNING' | 'TRACE': + # This needs to be handled by the individual task + pass + case _: + pass + + self.logger.debug(f'Importing module {self.taskname}') m = import_module('pysas.' + self.taskname + '.' + self.taskname) + self.logger.debug(f'Running module {self.taskname}') m.run(self.iparsdic) - + + # Reset Environment variables + for k, v in temp_dict.items(): + match(k): + case 'SAS_CCFPATH' | 'SAS_CCF' | 'SAS_ODF' | 'SAS_VERBOSITY': + self.logger.debug(f'Resetting {k} to {temp_dict[k]}') + if temp_dict[k] is None: + os.environ.pop(k,None) + else: + os.environ[k] = temp_dict[k] + case 'SAS_CLOBBER' | 'CCF_files' | 'WARNING' | 'TRACE': + # This needs to be handled by the individual task + pass + case _: + pass + + # For all other SAS tasks else: # Build a list of parameters based on iparsdic + self.logger.debug(f'Using non-Python based SAS task: {self.taskname}') cmd_list = [] cmd_list.append(self.taskname) for k, v in self.iparsdic.items(): @@ -444,8 +507,6 @@ def run(self): # For non-Python SAS tasks the stout and stderr are combined for line in process.stdout: logger.info(f"{line.strip()}") - # for line in process.stderr: - # logger.info(f"{line.strip()}") # Wait for the process to complete and get the return code process.wait() From bc021df7757422a9855b10181426567f7b82e5a4 Mon Sep 17 00:00:00 2001 From: rjtanner Date: Fri, 18 Jul 2025 15:13:01 -0400 Subject: [PATCH 15/17] Update gitignore --- .gitignore | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/.gitignore b/.gitignore index 2879438..78be7d3 100644 --- a/.gitignore +++ b/.gitignore @@ -1,4 +1,5 @@ *.log __pycache__ **/__pycache__/ -.venv \ No newline at end of file +.venv +.ipynb_checkpoints \ No newline at end of file From 0eab42ed0288b36a41d5f4223364122f7eaca0f4 Mon Sep 17 00:00:00 2001 From: rjtanner Date: Fri, 18 Jul 2025 15:30:19 -0400 Subject: [PATCH 16/17] Clean up and add documentation --- .ipynb_checkpoints/README-checkpoint.md | 109 ------------------------ odfcontrol/odfcontrol.py | 9 ++ parser.py | 47 +++++----- sastask.py | 10 +-- wrapper.py | 6 +- 5 files changed, 38 insertions(+), 143 deletions(-) delete mode 100644 .ipynb_checkpoints/README-checkpoint.md diff --git a/.ipynb_checkpoints/README-checkpoint.md b/.ipynb_checkpoints/README-checkpoint.md deleted file mode 100644 index 56b064b..0000000 --- a/.ipynb_checkpoints/README-checkpoint.md +++ /dev/null @@ -1,109 +0,0 @@ -### Installing pySAS - -This development version of pySAS can be used with versions 20 and up of XMM-Newton SAS. After installing SAS [following the installation instructions](https://www.cosmos.esa.int/web/xmm-newton/sas-installation) you can then install the development version of pySAS using -``` -pip install xmmpysas -``` -**Note:** Make sure you install **xmmpysas**. There is different Python module called *pysas* that has nothing to with pySAS for XMM-Newton. - -**Note:** Requires Python version >=3.10. - -Before you use pySAS for the first time you will need to configure pySAS so that it knows where you have SAS installed, and where the XMM calibration files are located. After installing pySAS using pip, in Python just run: -```python -import pysas -pysas.config_pysas.run_config() -``` -This will step you through connecting pySAS to SAS. After pySAS has been configured you can import pySAS like normal. -```python -import pysas -``` -You can update pySAS using -``` -pip install xmmpysas --upgrade -``` - -### Cloning This Repository - -*Alternatively*, pySAS can be cloned from GitHub by going into the directory where pySAS is installed to remove the current version of pySAS using -``` -cd /path/to/sas/install/xmmsas_202XXXXXX_YYYY/lib/python/ -rm -rf ./pysas -``` -and then clone this version of pySAS by executing the command, -``` -git clone https://github.com/XMMGOF/pysas.git -``` -You can then use pySAS like normal. - -To incorporate new changes to pySAS from GitHub, from the pysas directory use the following command, -``` -git pull https://github.com/XMMGOF/pysas.git -``` - -### Running pySAS for the First Time - -The very first time you run this version of pySAS you will have to set SAS defaults that will be used by pySAS. To set the defaults run the following commands in python: -```python -import pysas -pysas.config_pysas.run_config() -``` -This script will set: - -- sas_dir: The directory where SAS is installed. If you are running the script from inside the SAS directory this will be auto-detected. -- sas_ccfpath: The directory where the calibration files are stored. If you already have them downloaded, just enter the directory where they are. But if you have not downloaded them yet, you will be given the option to download them after the setup. The script will even create the directory for you. -- data_dir: You will have the option of designating a defaut data directory. All observation data files will be downloaded into this directory. If the data directory does not exist it will be created for you. - -**Note:** If you installed pySAS by cloning it from GitHub you must add the pySAS directory to your PYTHONPATH environment variable. For example: -``` -export PYTHONPATH=/path/to/sas/install/xmmsas_202XXXXXX_YYYY/lib/python:$PYTHONPATH -``` -It is recommended that you add this line to your .bash_profile file (or equivelent shell file). -**This is not necessary if pySAS was installed using `pip install xmmpysas`.** - -### Example Scripts - -There are example scripts and Jupyter notebooks available on [GitHub demonstrating how to use pySAS](https://github.com/XMMGOF/pysas/tree/main/documentation). We are expanding the number of example scripts and Jupyter notebooks. - -### FAQ - -Q: Will this break my SAS inatallation? - -A: No. All changes have been made to keep this developmental version of pySAS working with SAS. - -Q: I have already been working with pySAS and I have several Python scripts already written. Will this make them break? - -A: No. This developmental version of pySAS is fully backwards compatible with the standard pySAS distributed with SAS. The develomental version only adds capabilites. The features included here will eventually work their way into the standard version of pySAS. - -Q: Can I contribute changes to pySAS? - -A: YES! That is the purpose of this repository! The whole idea is to provide a place where changes can be made and tested, issues can be raised, and features can be requested for pySAS. User input is greatly encouraged. - -Q: Can I use pip to install pySAS? - -A: Yes! Install using -``` -pip install xmmpysas -``` - -Q: What about using conda to install pySAS? - -A: We are working on it! - -Q: Can I use pySAS to update the XMM-Newton calibration files? - -A: Yes! Just start a Python session and run the following commands: - -```python -import pysas -pysas.sasutils.update_calibration_files() -``` - -This will download new calibration files. - -Q: What version of pySAS is installed on SciServer? - -A: Version 2.0. - -Q: Why have this version of pySAS separate from the standard version you can download from ESA when you download SAS? - -A: Because of the realities of developing across multiple systems. Changes were needed to make pySAS run on systems such as SciServer (and other future online systems that are in the works, stay tuned!). The development timetable for SciServer did not match up with the development timetable for SAS. This allows us to continuously develop pySAS to match *all* of the development timetables. This also allows us to get feedback from the XMM-Newton user community about what they want to see in pySAS. diff --git a/odfcontrol/odfcontrol.py b/odfcontrol/odfcontrol.py index 244e69a..d16c451 100644 --- a/odfcontrol/odfcontrol.py +++ b/odfcontrol/odfcontrol.py @@ -27,6 +27,7 @@ # Standard library imports import os, sys, shutil, glob, numbers +from warnings import warn # Third party imports @@ -84,6 +85,14 @@ class ODFobject(object): """ def __init__(self,odfid,data_dir=None): + warn( + """ + The ODFobject class has been depricated. Use ObsID instead. + ex: + my_obs = pysas.obsid.ObsID(obsid) + instead of + odf = pysas.odfcontrol.ODFobject(obsid) + """) if isinstance(odfid, numbers.Number): odfid = str(odfid) self.odfid = odfid diff --git a/parser.py b/parser.py index 15e7d27..b687ccd 100644 --- a/parser.py +++ b/parser.py @@ -45,7 +45,6 @@ import subprocess import argparse from importlib import import_module -from contextlib import suppress import importlib.resources # Third party imports @@ -194,7 +193,7 @@ def optparser(self): #print(f'vars(self.parsedargs) = \n{vars(self.parsedargs)}') #print(f'self.parsedargs.pvpairs = {self.parsedargs.pvpairs}') - # Depending on the options entered, performs actions + # If these options are present, will execute a command and return Exit def exe_options(self): """ Method to execute options or parameters that @@ -212,6 +211,23 @@ def exe_options(self): Returns 'Exit' which if True will send the exit command up the chain. If False, then pySAS will continue to execute. + + # Process options entered in command line + # + # Options version(--version, -v), help(--help, -h), param(--param, -p) + # dialog(--dialog, -d) and manpage(--manpage, -m) are exclusive. + # Only one can be present and will set Exit to True. + # When exe_options is executed on the instance of ParseArgs (e.g. p), as + # p.exe_options() the return Exit determines wheter to return immediately or + # not. If Exit is set to True, the method will return immediately. + # + # Some options entered in self.argdict will launch special SAS tasks + # designed only to provide specific result. These are: + # + # -d/--dialog => sasdialog to launch task GUI + # -m/--manpage => sashelp to show HTML doc in the default web browser + # + """ # Exit is set to False @@ -242,24 +258,6 @@ def exe_options(self): ... """ - - # Process options entered in command line - # - # Options version(--version, -v), help(--help, -h), param(--param, -p) - # dialog(--dialog, -d) and manpage(--manpage, -m) are exclusive. - # Only one can be present and will set Exit to True. - # When procopt is executed on the instance of ParseArgs (e.g. p), as - # p.procopt() the return Exit determines wheter to return immediately or - # not. If Exit is set to True, the method will return immediately. - # - # Some options entered in self.argdict will launch special SAS tasks - # designed only to provide specific result. These are: - # - # -d/--dialog => sasdialog to launch task GUI - # -m/--manpage => sashelp to show HTML doc in the default web browser - # - - # Version: if self.parsedargs.version: print(f'{self.version}') @@ -292,11 +290,11 @@ def exe_options(self): if Exit: return Exit + # If these options are present, they will be returned for handling def env_options(self): """ - Method to execute options or parameters that - set environment variables and then continue running - the SAS task. These are: + Method to collect options that set environment variables + and then continue running the SAS task. These are: -V/--verbosity (SAS_VERBOSITY) -c/--noclobber (SAS_CLOBBER) @@ -306,9 +304,6 @@ def env_options(self): -f/--ccffiles -w/--warning -t/--trace - - Depending on the action, previously set values - will be returned. """ # return_options is a dictionary to hold set options return_options = {} diff --git a/sastask.py b/sastask.py index dcc8c4f..b35faf9 100644 --- a/sastask.py +++ b/sastask.py @@ -230,10 +230,11 @@ def readparfile(self): - mandpar : List of all mandatory parameters/subparameters - mainparams: List of main paramaters - parmap : Dictionary { pname: [ subparameters ...], ...} - - mandpar_dict: Dictionary, key = mandatory subparamater, value=its parent parameter - - rev_mandpar_dict: Dictionary, keys = parent paramater, + - mandpar_dict: Dictionary, key = mandatory subparamater, + value=its parent parameter + - rev_mandpar_dict: Dictionary, keys = parent paramater, value = list of all mandatory subparameters - - rev_mandpar_string_dict: Dictionary, keys = parent parameter type 'string' + - rev_mandpar_string_dict: Dictionary, keys = parent parameter type 'string' value = list of alternatives """ t = paramXmlInfoReader(self.taskname, logger = self.logger) @@ -267,14 +268,13 @@ def processargs(self): # Remove the options from argsdic self.argsdic = dict(self.inargs) - self.argsdic.pop('options') + self.argsdic.pop('options',None) # 1st check: Whether or not parameters in inargs are defined in the parameter file for p in self.argsdic.keys(): if p.strip() not in self.allparams.keys(): raise Exception(f'Parameter {p} is not defined in the parameter file') - # 2nd check: Whether we have mandatory parameters and subparameters for k, v in self.rev_mandpar_dict.items(): if k.strip() in v and k.strip() not in self.argsdic.keys(): diff --git a/wrapper.py b/wrapper.py index 608d994..981a205 100644 --- a/wrapper.py +++ b/wrapper.py @@ -18,7 +18,7 @@ """wrapper.py This file is only here for legacy reasons. Its only purpose -is to point to the SASTask class in sastask.py. +is to point to the MyTask class in sastask.py. """ # Standard library imports @@ -33,9 +33,9 @@ class Wrapper: """Class Wrapper This class is only here for legacy reasons. Its only purpose - is to point to the SASTask class in sastask.py. + is to point to the MyTask class in sastask.py. - Method run instantiates SASTask and calls 'run' from SASTask. + Method run instantiates MyTask and calls 'run' from MyTask. """ def __init__(self, taskname, inargs, logfilename = None, From 23af41831cc5fb88922313905e992d3781f2b2cb Mon Sep 17 00:00:00 2001 From: rjtanner Date: Fri, 18 Jul 2025 15:33:13 -0400 Subject: [PATCH 17/17] Bug fix --- logger.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/logger.py b/logger.py index e551e75..85ff586 100644 --- a/logger.py +++ b/logger.py @@ -100,8 +100,7 @@ def get_logger(taskname: str, if pylogger: # For Python based logging # Set verbosity - if verbosity is None: - verbosity = int(os.getenv('SAS_VERBOSITY')) + verbosity = int(os.getenv('SAS_VERBOSITY')) match(verbosity): case 1: level = "CRITICAL"