From 64969cb9ae43339c60c96af3e798a59bc7797d51 Mon Sep 17 00:00:00 2001 From: Gautzilla <72027971+Gautzilla@users.noreply.github.com> Date: Tue, 23 Sep 2025 17:23:23 +0200 Subject: [PATCH 01/13] add obspy to dependencies --- pyproject.toml | 1 + src/osekit/core_api/audio_file_manager.py | 13 +-- uv.lock | 134 ++++++++++++++++++---- 3 files changed, 119 insertions(+), 29 deletions(-) diff --git a/pyproject.toml b/pyproject.toml index d53340e6..abc727a4 100755 --- a/pyproject.toml +++ b/pyproject.toml @@ -11,6 +11,7 @@ dependencies = [ "matplotlib>=3.10.3", "notebook>=7.4.4", "numpy>=2.2.6", + "obspy>=1.4.2", "pandas>=2.2.3", "pytest>=8.3.5", "pyyaml>=6.0.2", diff --git a/src/osekit/core_api/audio_file_manager.py b/src/osekit/core_api/audio_file_manager.py index bc139f20..9bc27837 100644 --- a/src/osekit/core_api/audio_file_manager.py +++ b/src/osekit/core_api/audio_file_manager.py @@ -72,15 +72,14 @@ def read( stop = frames if not 0 <= start < frames: - raise ValueError( - "Start should be between 0 and the last frame of the audio file.", - ) + msg = "Start should be between 0 and the last frame of the audio file." + raise ValueError(msg) if not 0 <= stop <= frames: - raise ValueError( - "Stop should be between 0 and the last frame of the audio file.", - ) + msg = "Stop should be between 0 and the last frame of the audio file." + raise ValueError(msg) if start > stop: - raise ValueError("Start should be inferior to Stop.") + msg = "Start should be inferior to Stop." + raise ValueError(msg) self.opened_file.seek(start) return self.opened_file.read(stop - start) diff --git a/uv.lock b/uv.lock index 1a468b55..85c4651d 100644 --- a/uv.lock +++ b/uv.lock @@ -1192,6 +1192,86 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/2d/00/d90b10b962b4277f5e64a78b6609968859ff86889f5b898c1a778c06ec00/lark-1.2.2-py3-none-any.whl", hash = "sha256:c2276486b02f0f1b90be155f2c8ba4a8e194d42775786db622faccd652d8e80c", size = 111036, upload-time = "2024-08-13T19:48:58.603Z" }, ] +[[package]] +name = "lxml" +version = "6.0.2" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/aa/88/262177de60548e5a2bfc46ad28232c9e9cbde697bd94132aeb80364675cb/lxml-6.0.2.tar.gz", hash = "sha256:cd79f3367bd74b317dda655dc8fcfa304d9eb6e4fb06b7168c5cf27f96e0cd62", size = 4073426, upload-time = "2025-09-22T04:04:59.287Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/f3/c8/8ff2bc6b920c84355146cd1ab7d181bc543b89241cfb1ebee824a7c81457/lxml-6.0.2-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:a59f5448ba2ceccd06995c95ea59a7674a10de0810f2ce90c9006f3cbc044456", size = 8661887, upload-time = "2025-09-22T04:01:17.265Z" }, + { url = "https://files.pythonhosted.org/packages/37/6f/9aae1008083bb501ef63284220ce81638332f9ccbfa53765b2b7502203cf/lxml-6.0.2-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:e8113639f3296706fbac34a30813929e29247718e88173ad849f57ca59754924", size = 4667818, upload-time = "2025-09-22T04:01:19.688Z" }, + { url = "https://files.pythonhosted.org/packages/f1/ca/31fb37f99f37f1536c133476674c10b577e409c0a624384147653e38baf2/lxml-6.0.2-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:a8bef9b9825fa8bc816a6e641bb67219489229ebc648be422af695f6e7a4fa7f", size = 4950807, upload-time = "2025-09-22T04:01:21.487Z" }, + { url = "https://files.pythonhosted.org/packages/da/87/f6cb9442e4bada8aab5ae7e1046264f62fdbeaa6e3f6211b93f4c0dd97f1/lxml-6.0.2-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:65ea18d710fd14e0186c2f973dc60bb52039a275f82d3c44a0e42b43440ea534", size = 5109179, upload-time = "2025-09-22T04:01:23.32Z" }, + { url = "https://files.pythonhosted.org/packages/c8/20/a7760713e65888db79bbae4f6146a6ae5c04e4a204a3c48896c408cd6ed2/lxml-6.0.2-cp312-cp312-manylinux_2_26_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:c371aa98126a0d4c739ca93ceffa0fd7a5d732e3ac66a46e74339acd4d334564", size = 5023044, upload-time = "2025-09-22T04:01:25.118Z" }, + { url = "https://files.pythonhosted.org/packages/a2/b0/7e64e0460fcb36471899f75831509098f3fd7cd02a3833ac517433cb4f8f/lxml-6.0.2-cp312-cp312-manylinux_2_26_i686.manylinux_2_28_i686.whl", hash = "sha256:700efd30c0fa1a3581d80a748157397559396090a51d306ea59a70020223d16f", size = 5359685, upload-time = "2025-09-22T04:01:27.398Z" }, + { url = "https://files.pythonhosted.org/packages/b9/e1/e5df362e9ca4e2f48ed6411bd4b3a0ae737cc842e96877f5bf9428055ab4/lxml-6.0.2-cp312-cp312-manylinux_2_26_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:c33e66d44fe60e72397b487ee92e01da0d09ba2d66df8eae42d77b6d06e5eba0", size = 5654127, upload-time = "2025-09-22T04:01:29.629Z" }, + { url = "https://files.pythonhosted.org/packages/c6/d1/232b3309a02d60f11e71857778bfcd4acbdb86c07db8260caf7d008b08f8/lxml-6.0.2-cp312-cp312-manylinux_2_26_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:90a345bbeaf9d0587a3aaffb7006aa39ccb6ff0e96a57286c0cb2fd1520ea192", size = 5253958, upload-time = "2025-09-22T04:01:31.535Z" }, + { url = "https://files.pythonhosted.org/packages/35/35/d955a070994725c4f7d80583a96cab9c107c57a125b20bb5f708fe941011/lxml-6.0.2-cp312-cp312-manylinux_2_31_armv7l.whl", hash = "sha256:064fdadaf7a21af3ed1dcaa106b854077fbeada827c18f72aec9346847cd65d0", size = 4711541, upload-time = "2025-09-22T04:01:33.801Z" }, + { url = "https://files.pythonhosted.org/packages/1e/be/667d17363b38a78c4bd63cfd4b4632029fd68d2c2dc81f25ce9eb5224dd5/lxml-6.0.2-cp312-cp312-manylinux_2_38_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:fbc74f42c3525ac4ffa4b89cbdd00057b6196bcefe8bce794abd42d33a018092", size = 5267426, upload-time = "2025-09-22T04:01:35.639Z" }, + { url = "https://files.pythonhosted.org/packages/ea/47/62c70aa4a1c26569bc958c9ca86af2bb4e1f614e8c04fb2989833874f7ae/lxml-6.0.2-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:6ddff43f702905a4e32bc24f3f2e2edfe0f8fde3277d481bffb709a4cced7a1f", size = 5064917, upload-time = "2025-09-22T04:01:37.448Z" }, + { url = "https://files.pythonhosted.org/packages/bd/55/6ceddaca353ebd0f1908ef712c597f8570cc9c58130dbb89903198e441fd/lxml-6.0.2-cp312-cp312-musllinux_1_2_armv7l.whl", hash = "sha256:6da5185951d72e6f5352166e3da7b0dc27aa70bd1090b0eb3f7f7212b53f1bb8", size = 4788795, upload-time = "2025-09-22T04:01:39.165Z" }, + { url = "https://files.pythonhosted.org/packages/cf/e8/fd63e15da5e3fd4c2146f8bbb3c14e94ab850589beab88e547b2dbce22e1/lxml-6.0.2-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:57a86e1ebb4020a38d295c04fc79603c7899e0df71588043eb218722dabc087f", size = 5676759, upload-time = "2025-09-22T04:01:41.506Z" }, + { url = "https://files.pythonhosted.org/packages/76/47/b3ec58dc5c374697f5ba37412cd2728f427d056315d124dd4b61da381877/lxml-6.0.2-cp312-cp312-musllinux_1_2_riscv64.whl", hash = "sha256:2047d8234fe735ab77802ce5f2297e410ff40f5238aec569ad7c8e163d7b19a6", size = 5255666, upload-time = "2025-09-22T04:01:43.363Z" }, + { url = "https://files.pythonhosted.org/packages/19/93/03ba725df4c3d72afd9596eef4a37a837ce8e4806010569bedfcd2cb68fd/lxml-6.0.2-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:6f91fd2b2ea15a6800c8e24418c0775a1694eefc011392da73bc6cef2623b322", size = 5277989, upload-time = "2025-09-22T04:01:45.215Z" }, + { url = "https://files.pythonhosted.org/packages/c6/80/c06de80bfce881d0ad738576f243911fccf992687ae09fd80b734712b39c/lxml-6.0.2-cp312-cp312-win32.whl", hash = "sha256:3ae2ce7d6fedfb3414a2b6c5e20b249c4c607f72cb8d2bb7cc9c6ec7c6f4e849", size = 3611456, upload-time = "2025-09-22T04:01:48.243Z" }, + { url = "https://files.pythonhosted.org/packages/f7/d7/0cdfb6c3e30893463fb3d1e52bc5f5f99684a03c29a0b6b605cfae879cd5/lxml-6.0.2-cp312-cp312-win_amd64.whl", hash = "sha256:72c87e5ee4e58a8354fb9c7c84cbf95a1c8236c127a5d1b7683f04bed8361e1f", size = 4011793, upload-time = "2025-09-22T04:01:50.042Z" }, + { url = "https://files.pythonhosted.org/packages/ea/7b/93c73c67db235931527301ed3785f849c78991e2e34f3fd9a6663ffda4c5/lxml-6.0.2-cp312-cp312-win_arm64.whl", hash = "sha256:61cb10eeb95570153e0c0e554f58df92ecf5109f75eacad4a95baa709e26c3d6", size = 3672836, upload-time = "2025-09-22T04:01:52.145Z" }, + { url = "https://files.pythonhosted.org/packages/53/fd/4e8f0540608977aea078bf6d79f128e0e2c2bba8af1acf775c30baa70460/lxml-6.0.2-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:9b33d21594afab46f37ae58dfadd06636f154923c4e8a4d754b0127554eb2e77", size = 8648494, upload-time = "2025-09-22T04:01:54.242Z" }, + { url = "https://files.pythonhosted.org/packages/5d/f4/2a94a3d3dfd6c6b433501b8d470a1960a20ecce93245cf2db1706adf6c19/lxml-6.0.2-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:6c8963287d7a4c5c9a432ff487c52e9c5618667179c18a204bdedb27310f022f", size = 4661146, upload-time = "2025-09-22T04:01:56.282Z" }, + { url = "https://files.pythonhosted.org/packages/25/2e/4efa677fa6b322013035d38016f6ae859d06cac67437ca7dc708a6af7028/lxml-6.0.2-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:1941354d92699fb5ffe6ed7b32f9649e43c2feb4b97205f75866f7d21aa91452", size = 4946932, upload-time = "2025-09-22T04:01:58.989Z" }, + { url = "https://files.pythonhosted.org/packages/ce/0f/526e78a6d38d109fdbaa5049c62e1d32fdd70c75fb61c4eadf3045d3d124/lxml-6.0.2-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:bb2f6ca0ae2d983ded09357b84af659c954722bbf04dea98030064996d156048", size = 5100060, upload-time = "2025-09-22T04:02:00.812Z" }, + { url = "https://files.pythonhosted.org/packages/81/76/99de58d81fa702cc0ea7edae4f4640416c2062813a00ff24bd70ac1d9c9b/lxml-6.0.2-cp313-cp313-manylinux_2_26_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:eb2a12d704f180a902d7fa778c6d71f36ceb7b0d317f34cdc76a5d05aa1dd1df", size = 5019000, upload-time = "2025-09-22T04:02:02.671Z" }, + { url = "https://files.pythonhosted.org/packages/b5/35/9e57d25482bc9a9882cb0037fdb9cc18f4b79d85df94fa9d2a89562f1d25/lxml-6.0.2-cp313-cp313-manylinux_2_26_i686.manylinux_2_28_i686.whl", hash = "sha256:6ec0e3f745021bfed19c456647f0298d60a24c9ff86d9d051f52b509663feeb1", size = 5348496, upload-time = "2025-09-22T04:02:04.904Z" }, + { url = "https://files.pythonhosted.org/packages/a6/8e/cb99bd0b83ccc3e8f0f528e9aa1f7a9965dfec08c617070c5db8d63a87ce/lxml-6.0.2-cp313-cp313-manylinux_2_26_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:846ae9a12d54e368933b9759052d6206a9e8b250291109c48e350c1f1f49d916", size = 5643779, upload-time = "2025-09-22T04:02:06.689Z" }, + { url = "https://files.pythonhosted.org/packages/d0/34/9e591954939276bb679b73773836c6684c22e56d05980e31d52a9a8deb18/lxml-6.0.2-cp313-cp313-manylinux_2_26_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:ef9266d2aa545d7374938fb5c484531ef5a2ec7f2d573e62f8ce722c735685fd", size = 5244072, upload-time = "2025-09-22T04:02:08.587Z" }, + { url = "https://files.pythonhosted.org/packages/8d/27/b29ff065f9aaca443ee377aff699714fcbffb371b4fce5ac4ca759e436d5/lxml-6.0.2-cp313-cp313-manylinux_2_31_armv7l.whl", hash = "sha256:4077b7c79f31755df33b795dc12119cb557a0106bfdab0d2c2d97bd3cf3dffa6", size = 4718675, upload-time = "2025-09-22T04:02:10.783Z" }, + { url = "https://files.pythonhosted.org/packages/2b/9f/f756f9c2cd27caa1a6ef8c32ae47aadea697f5c2c6d07b0dae133c244fbe/lxml-6.0.2-cp313-cp313-manylinux_2_38_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:a7c5d5e5f1081955358533be077166ee97ed2571d6a66bdba6ec2f609a715d1a", size = 5255171, upload-time = "2025-09-22T04:02:12.631Z" }, + { url = "https://files.pythonhosted.org/packages/61/46/bb85ea42d2cb1bd8395484fd72f38e3389611aa496ac7772da9205bbda0e/lxml-6.0.2-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:8f8d0cbd0674ee89863a523e6994ac25fd5be9c8486acfc3e5ccea679bad2679", size = 5057175, upload-time = "2025-09-22T04:02:14.718Z" }, + { url = "https://files.pythonhosted.org/packages/95/0c/443fc476dcc8e41577f0af70458c50fe299a97bb6b7505bb1ae09aa7f9ac/lxml-6.0.2-cp313-cp313-musllinux_1_2_armv7l.whl", hash = "sha256:2cbcbf6d6e924c28f04a43f3b6f6e272312a090f269eff68a2982e13e5d57659", size = 4785688, upload-time = "2025-09-22T04:02:16.957Z" }, + { url = "https://files.pythonhosted.org/packages/48/78/6ef0b359d45bb9697bc5a626e1992fa5d27aa3f8004b137b2314793b50a0/lxml-6.0.2-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:dfb874cfa53340009af6bdd7e54ebc0d21012a60a4e65d927c2e477112e63484", size = 5660655, upload-time = "2025-09-22T04:02:18.815Z" }, + { url = "https://files.pythonhosted.org/packages/ff/ea/e1d33808f386bc1339d08c0dcada6e4712d4ed8e93fcad5f057070b7988a/lxml-6.0.2-cp313-cp313-musllinux_1_2_riscv64.whl", hash = "sha256:fb8dae0b6b8b7f9e96c26fdd8121522ce5de9bb5538010870bd538683d30e9a2", size = 5247695, upload-time = "2025-09-22T04:02:20.593Z" }, + { url = "https://files.pythonhosted.org/packages/4f/47/eba75dfd8183673725255247a603b4ad606f4ae657b60c6c145b381697da/lxml-6.0.2-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:358d9adae670b63e95bc59747c72f4dc97c9ec58881d4627fe0120da0f90d314", size = 5269841, upload-time = "2025-09-22T04:02:22.489Z" }, + { url = "https://files.pythonhosted.org/packages/76/04/5c5e2b8577bc936e219becb2e98cdb1aca14a4921a12995b9d0c523502ae/lxml-6.0.2-cp313-cp313-win32.whl", hash = "sha256:e8cd2415f372e7e5a789d743d133ae474290a90b9023197fd78f32e2dc6873e2", size = 3610700, upload-time = "2025-09-22T04:02:24.465Z" }, + { url = "https://files.pythonhosted.org/packages/fe/0a/4643ccc6bb8b143e9f9640aa54e38255f9d3b45feb2cbe7ae2ca47e8782e/lxml-6.0.2-cp313-cp313-win_amd64.whl", hash = "sha256:b30d46379644fbfc3ab81f8f82ae4de55179414651f110a1514f0b1f8f6cb2d7", size = 4010347, upload-time = "2025-09-22T04:02:26.286Z" }, + { url = "https://files.pythonhosted.org/packages/31/ef/dcf1d29c3f530577f61e5fe2f1bd72929acf779953668a8a47a479ae6f26/lxml-6.0.2-cp313-cp313-win_arm64.whl", hash = "sha256:13dcecc9946dca97b11b7c40d29fba63b55ab4170d3c0cf8c0c164343b9bfdcf", size = 3671248, upload-time = "2025-09-22T04:02:27.918Z" }, + { url = "https://files.pythonhosted.org/packages/03/15/d4a377b385ab693ce97b472fe0c77c2b16ec79590e688b3ccc71fba19884/lxml-6.0.2-cp314-cp314-macosx_10_13_universal2.whl", hash = "sha256:b0c732aa23de8f8aec23f4b580d1e52905ef468afb4abeafd3fec77042abb6fe", size = 8659801, upload-time = "2025-09-22T04:02:30.113Z" }, + { url = "https://files.pythonhosted.org/packages/c8/e8/c128e37589463668794d503afaeb003987373c5f94d667124ffd8078bbd9/lxml-6.0.2-cp314-cp314-macosx_10_13_x86_64.whl", hash = "sha256:4468e3b83e10e0317a89a33d28f7aeba1caa4d1a6fd457d115dd4ffe90c5931d", size = 4659403, upload-time = "2025-09-22T04:02:32.119Z" }, + { url = "https://files.pythonhosted.org/packages/00/ce/74903904339decdf7da7847bb5741fc98a5451b42fc419a86c0c13d26fe2/lxml-6.0.2-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:abd44571493973bad4598a3be7e1d807ed45aa2adaf7ab92ab7c62609569b17d", size = 4966974, upload-time = "2025-09-22T04:02:34.155Z" }, + { url = "https://files.pythonhosted.org/packages/1f/d3/131dec79ce61c5567fecf82515bd9bc36395df42501b50f7f7f3bd065df0/lxml-6.0.2-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:370cd78d5855cfbffd57c422851f7d3864e6ae72d0da615fca4dad8c45d375a5", size = 5102953, upload-time = "2025-09-22T04:02:36.054Z" }, + { url = "https://files.pythonhosted.org/packages/3a/ea/a43ba9bb750d4ffdd885f2cd333572f5bb900cd2408b67fdda07e85978a0/lxml-6.0.2-cp314-cp314-manylinux_2_26_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:901e3b4219fa04ef766885fb40fa516a71662a4c61b80c94d25336b4934b71c0", size = 5055054, upload-time = "2025-09-22T04:02:38.154Z" }, + { url = "https://files.pythonhosted.org/packages/60/23/6885b451636ae286c34628f70a7ed1fcc759f8d9ad382d132e1c8d3d9bfd/lxml-6.0.2-cp314-cp314-manylinux_2_26_i686.manylinux_2_28_i686.whl", hash = "sha256:a4bf42d2e4cf52c28cc1812d62426b9503cdb0c87a6de81442626aa7d69707ba", size = 5352421, upload-time = "2025-09-22T04:02:40.413Z" }, + { url = "https://files.pythonhosted.org/packages/48/5b/fc2ddfc94ddbe3eebb8e9af6e3fd65e2feba4967f6a4e9683875c394c2d8/lxml-6.0.2-cp314-cp314-manylinux_2_26_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:b2c7fdaa4d7c3d886a42534adec7cfac73860b89b4e5298752f60aa5984641a0", size = 5673684, upload-time = "2025-09-22T04:02:42.288Z" }, + { url = "https://files.pythonhosted.org/packages/29/9c/47293c58cc91769130fbf85531280e8cc7868f7fbb6d92f4670071b9cb3e/lxml-6.0.2-cp314-cp314-manylinux_2_26_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:98a5e1660dc7de2200b00d53fa00bcd3c35a3608c305d45a7bbcaf29fa16e83d", size = 5252463, upload-time = "2025-09-22T04:02:44.165Z" }, + { url = "https://files.pythonhosted.org/packages/9b/da/ba6eceb830c762b48e711ded880d7e3e89fc6c7323e587c36540b6b23c6b/lxml-6.0.2-cp314-cp314-manylinux_2_31_armv7l.whl", hash = "sha256:dc051506c30b609238d79eda75ee9cab3e520570ec8219844a72a46020901e37", size = 4698437, upload-time = "2025-09-22T04:02:46.524Z" }, + { url = "https://files.pythonhosted.org/packages/a5/24/7be3f82cb7990b89118d944b619e53c656c97dc89c28cfb143fdb7cd6f4d/lxml-6.0.2-cp314-cp314-manylinux_2_38_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:8799481bbdd212470d17513a54d568f44416db01250f49449647b5ab5b5dccb9", size = 5269890, upload-time = "2025-09-22T04:02:48.812Z" }, + { url = "https://files.pythonhosted.org/packages/1b/bd/dcfb9ea1e16c665efd7538fc5d5c34071276ce9220e234217682e7d2c4a5/lxml-6.0.2-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:9261bb77c2dab42f3ecd9103951aeca2c40277701eb7e912c545c1b16e0e4917", size = 5097185, upload-time = "2025-09-22T04:02:50.746Z" }, + { url = "https://files.pythonhosted.org/packages/21/04/a60b0ff9314736316f28316b694bccbbabe100f8483ad83852d77fc7468e/lxml-6.0.2-cp314-cp314-musllinux_1_2_armv7l.whl", hash = "sha256:65ac4a01aba353cfa6d5725b95d7aed6356ddc0a3cd734de00124d285b04b64f", size = 4745895, upload-time = "2025-09-22T04:02:52.968Z" }, + { url = "https://files.pythonhosted.org/packages/d6/bd/7d54bd1846e5a310d9c715921c5faa71cf5c0853372adf78aee70c8d7aa2/lxml-6.0.2-cp314-cp314-musllinux_1_2_ppc64le.whl", hash = "sha256:b22a07cbb82fea98f8a2fd814f3d1811ff9ed76d0fc6abc84eb21527596e7cc8", size = 5695246, upload-time = "2025-09-22T04:02:54.798Z" }, + { url = "https://files.pythonhosted.org/packages/fd/32/5643d6ab947bc371da21323acb2a6e603cedbe71cb4c99c8254289ab6f4e/lxml-6.0.2-cp314-cp314-musllinux_1_2_riscv64.whl", hash = "sha256:d759cdd7f3e055d6bc8d9bec3ad905227b2e4c785dc16c372eb5b5e83123f48a", size = 5260797, upload-time = "2025-09-22T04:02:57.058Z" }, + { url = "https://files.pythonhosted.org/packages/33/da/34c1ec4cff1eea7d0b4cd44af8411806ed943141804ac9c5d565302afb78/lxml-6.0.2-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:945da35a48d193d27c188037a05fec5492937f66fb1958c24fc761fb9d40d43c", size = 5277404, upload-time = "2025-09-22T04:02:58.966Z" }, + { url = "https://files.pythonhosted.org/packages/82/57/4eca3e31e54dc89e2c3507e1cd411074a17565fa5ffc437c4ae0a00d439e/lxml-6.0.2-cp314-cp314-win32.whl", hash = "sha256:be3aaa60da67e6153eb15715cc2e19091af5dc75faef8b8a585aea372507384b", size = 3670072, upload-time = "2025-09-22T04:03:38.05Z" }, + { url = "https://files.pythonhosted.org/packages/e3/e0/c96cf13eccd20c9421ba910304dae0f619724dcf1702864fd59dd386404d/lxml-6.0.2-cp314-cp314-win_amd64.whl", hash = "sha256:fa25afbadead523f7001caf0c2382afd272c315a033a7b06336da2637d92d6ed", size = 4080617, upload-time = "2025-09-22T04:03:39.835Z" }, + { url = "https://files.pythonhosted.org/packages/d5/5d/b3f03e22b3d38d6f188ef044900a9b29b2fe0aebb94625ce9fe244011d34/lxml-6.0.2-cp314-cp314-win_arm64.whl", hash = "sha256:063eccf89df5b24e361b123e257e437f9e9878f425ee9aae3144c77faf6da6d8", size = 3754930, upload-time = "2025-09-22T04:03:41.565Z" }, + { url = "https://files.pythonhosted.org/packages/5e/5c/42c2c4c03554580708fc738d13414801f340c04c3eff90d8d2d227145275/lxml-6.0.2-cp314-cp314t-macosx_10_13_universal2.whl", hash = "sha256:6162a86d86893d63084faaf4ff937b3daea233e3682fb4474db07395794fa80d", size = 8910380, upload-time = "2025-09-22T04:03:01.645Z" }, + { url = "https://files.pythonhosted.org/packages/bf/4f/12df843e3e10d18d468a7557058f8d3733e8b6e12401f30b1ef29360740f/lxml-6.0.2-cp314-cp314t-macosx_10_13_x86_64.whl", hash = "sha256:414aaa94e974e23a3e92e7ca5b97d10c0cf37b6481f50911032c69eeb3991bba", size = 4775632, upload-time = "2025-09-22T04:03:03.814Z" }, + { url = "https://files.pythonhosted.org/packages/e4/0c/9dc31e6c2d0d418483cbcb469d1f5a582a1cd00a1f4081953d44051f3c50/lxml-6.0.2-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:48461bd21625458dd01e14e2c38dd0aea69addc3c4f960c30d9f59d7f93be601", size = 4975171, upload-time = "2025-09-22T04:03:05.651Z" }, + { url = "https://files.pythonhosted.org/packages/e7/2b/9b870c6ca24c841bdd887504808f0417aa9d8d564114689266f19ddf29c8/lxml-6.0.2-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:25fcc59afc57d527cfc78a58f40ab4c9b8fd096a9a3f964d2781ffb6eb33f4ed", size = 5110109, upload-time = "2025-09-22T04:03:07.452Z" }, + { url = "https://files.pythonhosted.org/packages/bf/0c/4f5f2a4dd319a178912751564471355d9019e220c20d7db3fb8307ed8582/lxml-6.0.2-cp314-cp314t-manylinux_2_26_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:5179c60288204e6ddde3f774a93350177e08876eaf3ab78aa3a3649d43eb7d37", size = 5041061, upload-time = "2025-09-22T04:03:09.297Z" }, + { url = "https://files.pythonhosted.org/packages/12/64/554eed290365267671fe001a20d72d14f468ae4e6acef1e179b039436967/lxml-6.0.2-cp314-cp314t-manylinux_2_26_i686.manylinux_2_28_i686.whl", hash = "sha256:967aab75434de148ec80597b75062d8123cadf2943fb4281f385141e18b21338", size = 5306233, upload-time = "2025-09-22T04:03:11.651Z" }, + { url = "https://files.pythonhosted.org/packages/7a/31/1d748aa275e71802ad9722df32a7a35034246b42c0ecdd8235412c3396ef/lxml-6.0.2-cp314-cp314t-manylinux_2_26_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:d100fcc8930d697c6561156c6810ab4a508fb264c8b6779e6e61e2ed5e7558f9", size = 5604739, upload-time = "2025-09-22T04:03:13.592Z" }, + { url = "https://files.pythonhosted.org/packages/8f/41/2c11916bcac09ed561adccacceaedd2bf0e0b25b297ea92aab99fd03d0fa/lxml-6.0.2-cp314-cp314t-manylinux_2_26_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:2ca59e7e13e5981175b8b3e4ab84d7da57993eeff53c07764dcebda0d0e64ecd", size = 5225119, upload-time = "2025-09-22T04:03:15.408Z" }, + { url = "https://files.pythonhosted.org/packages/99/05/4e5c2873d8f17aa018e6afde417c80cc5d0c33be4854cce3ef5670c49367/lxml-6.0.2-cp314-cp314t-manylinux_2_31_armv7l.whl", hash = "sha256:957448ac63a42e2e49531b9d6c0fa449a1970dbc32467aaad46f11545be9af1d", size = 4633665, upload-time = "2025-09-22T04:03:17.262Z" }, + { url = "https://files.pythonhosted.org/packages/0f/c9/dcc2da1bebd6275cdc723b515f93edf548b82f36a5458cca3578bc899332/lxml-6.0.2-cp314-cp314t-manylinux_2_38_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:b7fc49c37f1786284b12af63152fe1d0990722497e2d5817acfe7a877522f9a9", size = 5234997, upload-time = "2025-09-22T04:03:19.14Z" }, + { url = "https://files.pythonhosted.org/packages/9c/e2/5172e4e7468afca64a37b81dba152fc5d90e30f9c83c7c3213d6a02a5ce4/lxml-6.0.2-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:e19e0643cc936a22e837f79d01a550678da8377d7d801a14487c10c34ee49c7e", size = 5090957, upload-time = "2025-09-22T04:03:21.436Z" }, + { url = "https://files.pythonhosted.org/packages/a5/b3/15461fd3e5cd4ddcb7938b87fc20b14ab113b92312fc97afe65cd7c85de1/lxml-6.0.2-cp314-cp314t-musllinux_1_2_armv7l.whl", hash = "sha256:1db01e5cf14345628e0cbe71067204db658e2fb8e51e7f33631f5f4735fefd8d", size = 4764372, upload-time = "2025-09-22T04:03:23.27Z" }, + { url = "https://files.pythonhosted.org/packages/05/33/f310b987c8bf9e61c4dd8e8035c416bd3230098f5e3cfa69fc4232de7059/lxml-6.0.2-cp314-cp314t-musllinux_1_2_ppc64le.whl", hash = "sha256:875c6b5ab39ad5291588aed6925fac99d0097af0dd62f33c7b43736043d4a2ec", size = 5634653, upload-time = "2025-09-22T04:03:25.767Z" }, + { url = "https://files.pythonhosted.org/packages/70/ff/51c80e75e0bc9382158133bdcf4e339b5886c6ee2418b5199b3f1a61ed6d/lxml-6.0.2-cp314-cp314t-musllinux_1_2_riscv64.whl", hash = "sha256:cdcbed9ad19da81c480dfd6dd161886db6096083c9938ead313d94b30aadf272", size = 5233795, upload-time = "2025-09-22T04:03:27.62Z" }, + { url = "https://files.pythonhosted.org/packages/56/4d/4856e897df0d588789dd844dbed9d91782c4ef0b327f96ce53c807e13128/lxml-6.0.2-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:80dadc234ebc532e09be1975ff538d154a7fa61ea5031c03d25178855544728f", size = 5257023, upload-time = "2025-09-22T04:03:30.056Z" }, + { url = "https://files.pythonhosted.org/packages/0f/85/86766dfebfa87bea0ab78e9ff7a4b4b45225df4b4d3b8cc3c03c5cd68464/lxml-6.0.2-cp314-cp314t-win32.whl", hash = "sha256:da08e7bb297b04e893d91087df19638dc7a6bb858a954b0cc2b9f5053c922312", size = 3911420, upload-time = "2025-09-22T04:03:32.198Z" }, + { url = "https://files.pythonhosted.org/packages/fe/1a/b248b355834c8e32614650b8008c69ffeb0ceb149c793961dd8c0b991bb3/lxml-6.0.2-cp314-cp314t-win_amd64.whl", hash = "sha256:252a22982dca42f6155125ac76d3432e548a7625d56f5a273ee78a5057216eca", size = 4406837, upload-time = "2025-09-22T04:03:34.027Z" }, + { url = "https://files.pythonhosted.org/packages/92/aa/df863bcc39c5e0946263454aba394de8a9084dbaff8ad143846b0d844739/lxml-6.0.2-cp314-cp314t-win_arm64.whl", hash = "sha256:bb4c1847b303835d89d785a18801a883436cdfd5dc3d62947f9c49e24f0f5a2c", size = 3822205, upload-time = "2025-09-22T04:03:36.249Z" }, +] + [[package]] name = "markdown-it-py" version = "3.0.0" @@ -1565,6 +1645,27 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/c1/9e/1652778bce745a67b5fe05adde60ed362d38eb17d919a540e813d30f6874/numpy-2.3.2-cp314-cp314t-win_arm64.whl", hash = "sha256:092aeb3449833ea9c0bf0089d70c29ae480685dd2377ec9cdbbb620257f84631", size = 10544226, upload-time = "2025-07-24T20:56:34.509Z" }, ] +[[package]] +name = "obspy" +version = "1.4.2" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "decorator" }, + { name = "lxml" }, + { name = "matplotlib" }, + { name = "numpy" }, + { name = "requests" }, + { name = "scipy" }, + { name = "setuptools" }, + { name = "sqlalchemy" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/13/98/108c3349aa18e2a2efb15d8cf7ab5b568f2f1a96d2411ce758546958d4ad/obspy-1.4.2.tar.gz", hash = "sha256:dd93a17cda32be057937b551f096df07def6aa61ccf26558ce9cd1866a70397c", size = 17036293, upload-time = "2025-04-30T12:45:15.835Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/e8/d0/64372c148fb552ea4b54fd9f44afed030430097a6b33540dcef7a195cae6/obspy-1.4.2-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:c24018ccdebf8cbc170af2dd9a86679f4baf074a7d645bdf017d50e3198baa8f", size = 14143750, upload-time = "2025-04-30T12:44:55.076Z" }, + { url = "https://files.pythonhosted.org/packages/ba/53/c1546cf83b763566b86dd2556276a92ab1e9900f77e4825898f1b810ec81/obspy-1.4.2-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:87bdde2cce9a12a85b77bd874bfe0d88457e8367aa21c653b78ab6c2e9f68622", size = 14523015, upload-time = "2025-04-30T12:44:57.576Z" }, + { url = "https://files.pythonhosted.org/packages/14/5f/e04dc347ae865c0c8e92aa9af8122d015fd1b85d5dd2bf29e522b6b94296/obspy-1.4.2-cp312-cp312-win_amd64.whl", hash = "sha256:a6fdd8693e55fada63e9bf36e5cbdfe1ebd231f4723fe1398ed6a7a4ee5de2ad", size = 14113148, upload-time = "2025-04-30T12:45:00.101Z" }, +] + [[package]] name = "osekit" version = "0.3.1" @@ -1573,6 +1674,7 @@ dependencies = [ { name = "matplotlib" }, { name = "notebook" }, { name = "numpy" }, + { name = "obspy" }, { name = "pandas" }, { name = "pytest" }, { name = "pyyaml" }, @@ -1602,6 +1704,7 @@ requires-dist = [ { name = "matplotlib", specifier = ">=3.10.3" }, { name = "notebook", specifier = ">=7.4.4" }, { name = "numpy", specifier = ">=2.2.6" }, + { name = "obspy", specifier = ">=1.4.2" }, { name = "pandas", specifier = ">=2.2.3" }, { name = "pytest", specifier = ">=8.3.5" }, { name = "pyyaml", specifier = ">=6.0.2" }, @@ -2533,31 +2636,18 @@ wheels = [ [[package]] name = "sqlalchemy" -version = "2.0.42" +version = "1.4.54" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "greenlet", marker = "(python_full_version < '3.14' and platform_machine == 'AMD64') or (python_full_version < '3.14' and platform_machine == 'WIN32') or (python_full_version < '3.14' and platform_machine == 'aarch64') or (python_full_version < '3.14' and platform_machine == 'amd64') or (python_full_version < '3.14' and platform_machine == 'ppc64le') or (python_full_version < '3.14' and platform_machine == 'win32') or (python_full_version < '3.14' and platform_machine == 'x86_64')" }, - { name = "typing-extensions" }, + { name = "greenlet", marker = "platform_machine == 'AMD64' or platform_machine == 'WIN32' or platform_machine == 'aarch64' or platform_machine == 'amd64' or platform_machine == 'ppc64le' or platform_machine == 'win32' or platform_machine == 'x86_64'" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/5a/03/a0af991e3a43174d6b83fca4fb399745abceddd1171bdabae48ce877ff47/sqlalchemy-2.0.42.tar.gz", hash = "sha256:160bedd8a5c28765bd5be4dec2d881e109e33b34922e50a3b881a7681773ac5f", size = 9749972, upload-time = "2025-07-29T12:48:09.323Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/61/66/ac31a9821fc70a7376321fb2c70fdd7eadbc06dadf66ee216a22a41d6058/sqlalchemy-2.0.42-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:09637a0872689d3eb71c41e249c6f422e3e18bbd05b4cd258193cfc7a9a50da2", size = 2132203, upload-time = "2025-07-29T13:29:19.291Z" }, - { url = "https://files.pythonhosted.org/packages/fc/ba/fd943172e017f955d7a8b3a94695265b7114efe4854feaa01f057e8f5293/sqlalchemy-2.0.42-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:a3cb3ec67cc08bea54e06b569398ae21623534a7b1b23c258883a7c696ae10df", size = 2120373, upload-time = "2025-07-29T13:29:21.049Z" }, - { url = "https://files.pythonhosted.org/packages/ea/a2/b5f7d233d063ffadf7e9fff3898b42657ba154a5bec95a96f44cba7f818b/sqlalchemy-2.0.42-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e87e6a5ef6f9d8daeb2ce5918bf5fddecc11cae6a7d7a671fcc4616c47635e01", size = 3317685, upload-time = "2025-07-29T13:26:40.837Z" }, - { url = "https://files.pythonhosted.org/packages/86/00/fcd8daab13a9119d41f3e485a101c29f5d2085bda459154ba354c616bf4e/sqlalchemy-2.0.42-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0b718011a9d66c0d2f78e1997755cd965f3414563b31867475e9bc6efdc2281d", size = 3326967, upload-time = "2025-07-29T13:22:31.009Z" }, - { url = "https://files.pythonhosted.org/packages/a3/85/e622a273d648d39d6771157961956991a6d760e323e273d15e9704c30ccc/sqlalchemy-2.0.42-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:16d9b544873fe6486dddbb859501a07d89f77c61d29060bb87d0faf7519b6a4d", size = 3255331, upload-time = "2025-07-29T13:26:42.579Z" }, - { url = "https://files.pythonhosted.org/packages/3a/a0/2c2338b592c7b0a61feffd005378c084b4c01fabaf1ed5f655ab7bd446f0/sqlalchemy-2.0.42-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:21bfdf57abf72fa89b97dd74d3187caa3172a78c125f2144764a73970810c4ee", size = 3291791, upload-time = "2025-07-29T13:22:32.454Z" }, - { url = "https://files.pythonhosted.org/packages/41/19/b8a2907972a78285fdce4c880ecaab3c5067eb726882ca6347f7a4bf64f6/sqlalchemy-2.0.42-cp312-cp312-win32.whl", hash = "sha256:78b46555b730a24901ceb4cb901c6b45c9407f8875209ed3c5d6bcd0390a6ed1", size = 2096180, upload-time = "2025-07-29T13:16:08.952Z" }, - { url = "https://files.pythonhosted.org/packages/48/1f/67a78f3dfd08a2ed1c7be820fe7775944f5126080b5027cc859084f8e223/sqlalchemy-2.0.42-cp312-cp312-win_amd64.whl", hash = "sha256:4c94447a016f36c4da80072e6c6964713b0af3c8019e9c4daadf21f61b81ab53", size = 2123533, upload-time = "2025-07-29T13:16:11.705Z" }, - { url = "https://files.pythonhosted.org/packages/e9/7e/25d8c28b86730c9fb0e09156f601d7a96d1c634043bf8ba36513eb78887b/sqlalchemy-2.0.42-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:941804f55c7d507334da38133268e3f6e5b0340d584ba0f277dd884197f4ae8c", size = 2127905, upload-time = "2025-07-29T13:29:22.249Z" }, - { url = "https://files.pythonhosted.org/packages/e5/a1/9d8c93434d1d983880d976400fcb7895a79576bd94dca61c3b7b90b1ed0d/sqlalchemy-2.0.42-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:95d3d06a968a760ce2aa6a5889fefcbdd53ca935735e0768e1db046ec08cbf01", size = 2115726, upload-time = "2025-07-29T13:29:23.496Z" }, - { url = "https://files.pythonhosted.org/packages/a2/cc/d33646fcc24c87cc4e30a03556b611a4e7bcfa69a4c935bffb923e3c89f4/sqlalchemy-2.0.42-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:4cf10396a8a700a0f38ccd220d940be529c8f64435c5d5b29375acab9267a6c9", size = 3246007, upload-time = "2025-07-29T13:26:44.166Z" }, - { url = "https://files.pythonhosted.org/packages/67/08/4e6c533d4c7f5e7c4cbb6fe8a2c4e813202a40f05700d4009a44ec6e236d/sqlalchemy-2.0.42-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9cae6c2b05326d7c2c7c0519f323f90e0fb9e8afa783c6a05bb9ee92a90d0f04", size = 3250919, upload-time = "2025-07-29T13:22:33.74Z" }, - { url = "https://files.pythonhosted.org/packages/5c/82/f680e9a636d217aece1b9a8030d18ad2b59b5e216e0c94e03ad86b344af3/sqlalchemy-2.0.42-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:f50f7b20677b23cfb35b6afcd8372b2feb348a38e3033f6447ee0704540be894", size = 3180546, upload-time = "2025-07-29T13:26:45.648Z" }, - { url = "https://files.pythonhosted.org/packages/7d/a2/8c8f6325f153894afa3775584c429cc936353fb1db26eddb60a549d0ff4b/sqlalchemy-2.0.42-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:9d88a1c0d66d24e229e3938e1ef16ebdbd2bf4ced93af6eff55225f7465cf350", size = 3216683, upload-time = "2025-07-29T13:22:34.977Z" }, - { url = "https://files.pythonhosted.org/packages/39/44/3a451d7fa4482a8ffdf364e803ddc2cfcafc1c4635fb366f169ecc2c3b11/sqlalchemy-2.0.42-cp313-cp313-win32.whl", hash = "sha256:45c842c94c9ad546c72225a0c0d1ae8ef3f7c212484be3d429715a062970e87f", size = 2093990, upload-time = "2025-07-29T13:16:13.036Z" }, - { url = "https://files.pythonhosted.org/packages/4b/9e/9bce34f67aea0251c8ac104f7bdb2229d58fb2e86a4ad8807999c4bee34b/sqlalchemy-2.0.42-cp313-cp313-win_amd64.whl", hash = "sha256:eb9905f7f1e49fd57a7ed6269bc567fcbbdac9feadff20ad6bd7707266a91577", size = 2120473, upload-time = "2025-07-29T13:16:14.502Z" }, - { url = "https://files.pythonhosted.org/packages/ee/55/ba2546ab09a6adebc521bf3974440dc1d8c06ed342cceb30ed62a8858835/sqlalchemy-2.0.42-py3-none-any.whl", hash = "sha256:defcdff7e661f0043daa381832af65d616e060ddb54d3fe4476f51df7eaa1835", size = 1922072, upload-time = "2025-07-29T13:09:17.061Z" }, +sdist = { url = "https://files.pythonhosted.org/packages/ce/af/20290b55d469e873cba9d41c0206ab5461ff49d759989b3fe65010f9d265/sqlalchemy-1.4.54.tar.gz", hash = "sha256:4470fbed088c35dc20b78a39aaf4ae54fe81790c783b3264872a0224f437c31a", size = 8470350, upload-time = "2024-09-05T15:54:10.398Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/a5/1b/aa9b99be95d1615f058b5827447c18505b7b3f1dfcbd6ce1b331c2107152/SQLAlchemy-1.4.54-cp312-cp312-macosx_10_9_universal2.whl", hash = "sha256:3f01c2629a7d6b30d8afe0326b8c649b74825a0e1ebdcb01e8ffd1c920deb07d", size = 1589983, upload-time = "2024-09-05T17:39:02.132Z" }, + { url = "https://files.pythonhosted.org/packages/59/47/cb0fc64e5344f0a3d02216796c342525ab283f8f052d1c31a1d487d08aa0/SQLAlchemy-1.4.54-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:9c24dd161c06992ed16c5e528a75878edbaeced5660c3db88c820f1f0d3fe1f4", size = 1630158, upload-time = "2024-09-05T17:50:13.255Z" }, + { url = "https://files.pythonhosted.org/packages/c0/8b/f45dd378f6c97e8ff9332ff3d03ecb0b8c491be5bb7a698783b5a2f358ec/SQLAlchemy-1.4.54-cp312-cp312-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b5e0d47d619c739bdc636bbe007da4519fc953393304a5943e0b5aec96c9877c", size = 1629232, upload-time = "2024-09-05T17:48:15.514Z" }, + { url = "https://files.pythonhosted.org/packages/0d/3c/884fe389f5bec86a310b81e79abaa1e26e5d78dc10a84d544a6822833e47/SQLAlchemy-1.4.54-cp312-cp312-win32.whl", hash = "sha256:12bc0141b245918b80d9d17eca94663dbd3f5266ac77a0be60750f36102bbb0f", size = 1592027, upload-time = "2024-09-05T17:54:02.253Z" }, + { url = "https://files.pythonhosted.org/packages/01/c3/c690d037be57efd3a69cde16a2ef1bd2a905dafe869434d33836de0983d0/SQLAlchemy-1.4.54-cp312-cp312-win_amd64.whl", hash = "sha256:f941aaf15f47f316123e1933f9ea91a6efda73a161a6ab6046d1cde37be62c88", size = 1593827, upload-time = "2024-09-05T17:52:07.454Z" }, ] [[package]] From 227f1c76d0198213720338f0b1a2d257600fa52b Mon Sep 17 00:00:00 2001 From: Gautzilla <72027971+Gautzilla@users.noreply.github.com> Date: Wed, 24 Sep 2025 11:53:47 +0200 Subject: [PATCH 02/13] read mseed metadata in AudioFile --- src/osekit/core_api/audio_file_manager.py | 32 +++++++++++++++++++++++ 1 file changed, 32 insertions(+) diff --git a/src/osekit/core_api/audio_file_manager.py b/src/osekit/core_api/audio_file_manager.py index 9bc27837..ce3a0bbf 100644 --- a/src/osekit/core_api/audio_file_manager.py +++ b/src/osekit/core_api/audio_file_manager.py @@ -5,8 +5,10 @@ from __future__ import annotations +from pathlib import Path from typing import TYPE_CHECKING +import obspy import soundfile as sf if TYPE_CHECKING: @@ -98,9 +100,39 @@ def info(self, path: PathLike | str) -> tuple[int, int, int]: Sample rate, number of frames and channels of the audio file. """ + if Path(path).suffix == ".mseed": + return self.mseed_info(path) + self._switch(path) return ( self.opened_file.samplerate, self.opened_file.frames, self.opened_file.channels, ) + + @staticmethod + def mseed_info(path: PathLike | str) -> tuple[int, int, int]: + """Return the sample rate, number of frames and channels of the mseed file. + + Parameters + ---------- + path: PathLike | str + Path to the mseed file. + + Returns + ------- + tuple[int,int,int]: + Sample rate, number of frames and channels of the mseed file. + + """ + metadata = obspy.read(pathname_or_url=path, headonly=True) + sample_rate = set(trace.meta.sampling_rate for trace in metadata.traces) + if len(sample_rate) != 1: + raise ValueError("Audio file has inconsistent sampling rate.") + sample_rate = sample_rate.pop() + frames = sum(trace.meta.npts for trace in metadata.traces) + return ( + sample_rate, + frames, + 1, + ) From d2d24443bc78acc773ef1d22fcc283fa06add516 Mon Sep 17 00:00:00 2001 From: Gautzilla <72027971+Gautzilla@users.noreply.github.com> Date: Wed, 24 Sep 2025 12:43:55 +0200 Subject: [PATCH 03/13] add afm mseed read data method --- src/osekit/core_api/audio_file_manager.py | 49 +++++++++++++++++------ 1 file changed, 37 insertions(+), 12 deletions(-) diff --git a/src/osekit/core_api/audio_file_manager.py b/src/osekit/core_api/audio_file_manager.py index ce3a0bbf..05c9d6cb 100644 --- a/src/osekit/core_api/audio_file_manager.py +++ b/src/osekit/core_api/audio_file_manager.py @@ -8,14 +8,13 @@ from pathlib import Path from typing import TYPE_CHECKING +import numpy as np import obspy import soundfile as sf if TYPE_CHECKING: from os import PathLike - import numpy as np - class AudioFileManager: """Audio File Manager which keeps an audio file open until a request in another file is made.""" @@ -42,6 +41,39 @@ def _switch(self, path: PathLike | str) -> None: self.close() self._open(path) + @staticmethod + def _check_boudaries(start: int, stop: int, frames: int) -> None: + if not 0 <= start < frames: + msg = "Start should be between 0 and the last frame of the audio file." + raise ValueError(msg) + if not 0 <= stop <= frames: + msg = "Stop should be between 0 and the last frame of the audio file." + raise ValueError(msg) + if start > stop: + msg = "Start should be inferior to Stop." + raise ValueError(msg) + + @staticmethod + def _read_mseed(path: PathLike | str, start: int, stop: int) -> np.ndarray: + """Read the content of a mseed file between the start and stop frames. + + Parameters + ---------- + path: PathLike | str + Path to the mseed file. + start: int + First frame to read. + stop: int + Frame after the last frame to read. + + Returns + ------- + np.ndarray: + A (stop-start)-long array containing the mseed audio data. + + """ + return np.concat([trace.data for trace in obspy.read(path).traces])[start:stop] + def read( self, path: PathLike | str, @@ -68,20 +100,13 @@ def read( A (channel * frames) array containing the audio data. """ - self._switch(path) _, frames, _ = self.info(path) if stop is None: stop = frames + self._check_boudaries(start=start, stop=stop, frames=frames) - if not 0 <= start < frames: - msg = "Start should be between 0 and the last frame of the audio file." - raise ValueError(msg) - if not 0 <= stop <= frames: - msg = "Stop should be between 0 and the last frame of the audio file." - raise ValueError(msg) - if start > stop: - msg = "Start should be inferior to Stop." - raise ValueError(msg) + if Path(path).suffix == ".mseed": + return self._read_mseed(path=path, start=start, stop=stop) self.opened_file.seek(start) return self.opened_file.read(stop - start) From 79be1e165ed052e2945488f3ae2738b502bd73a8 Mon Sep 17 00:00:00 2001 From: Gautzilla <72027971+Gautzilla@users.noreply.github.com> Date: Wed, 24 Sep 2025 15:15:29 +0200 Subject: [PATCH 04/13] add mseed files to supported audio formats --- src/osekit/core_api/audio_dataset.py | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/src/osekit/core_api/audio_dataset.py b/src/osekit/core_api/audio_dataset.py index bf38d4ed..069b7bca 100644 --- a/src/osekit/core_api/audio_dataset.py +++ b/src/osekit/core_api/audio_dataset.py @@ -235,7 +235,10 @@ def from_folder( # noqa: PLR0913 """ kwargs.update( - {"file_class": AudioFile, "supported_file_extensions": [".wav", ".flac"]}, + { + "file_class": AudioFile, + "supported_file_extensions": [".wav", ".flac", ".mseed"], + }, ) base_dataset = BaseDataset.from_folder( folder=folder, @@ -338,7 +341,9 @@ def from_base_dataset( return cls( [ AudioData.from_base_data( - data=data, sample_rate=sample_rate, normalization=normalization + data=data, + sample_rate=sample_rate, + normalization=normalization, ) for data in base_dataset.data ], From e6ebd4fae636824c94d5069bcc0f71ef438133bc Mon Sep 17 00:00:00 2001 From: Gautzilla <72027971+Gautzilla@users.noreply.github.com> Date: Wed, 24 Sep 2025 18:08:10 +0200 Subject: [PATCH 05/13] add test for mseed file --- tests/test_audio.py | 51 ++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 50 insertions(+), 1 deletion(-) diff --git a/tests/test_audio.py b/tests/test_audio.py index b50ab524..6710d109 100644 --- a/tests/test_audio.py +++ b/tests/test_audio.py @@ -6,6 +6,7 @@ from typing import Literal import numpy as np +import obspy import pandas as pd import pytest import soundfile as sf @@ -15,6 +16,7 @@ from osekit.config import ( TIMESTAMP_FORMAT_EXPORTED_FILES_LOCALIZED, TIMESTAMP_FORMAT_EXPORTED_FILES_UNLOCALIZED, + TIMESTAMP_FORMATS_EXPORTED_FILES, resample_quality_settings, ) from osekit.core_api import audio_file_manager as afm @@ -23,7 +25,7 @@ from osekit.core_api.audio_file import AudioFile from osekit.core_api.audio_item import AudioItem from osekit.utils import audio_utils -from osekit.utils.audio_utils import generate_sample_audio, Normalization, normalize +from osekit.utils.audio_utils import Normalization, generate_sample_audio, normalize @pytest.mark.parametrize( @@ -197,6 +199,53 @@ def test_audio_file_read( assert np.allclose(files[0].read(start, stop), expected, atol=1e-7) +@pytest.mark.parametrize( + ("streams", "files_begin", "begin", "end", "expected_data"), + [ + pytest.param( + [ + obspy.Stream( + obspy.Trace( + data=np.array(range(10), dtype=np.int32), + header={"sampling_rate": 0.1}, + ), + ), + ], + [Timestamp("2002-04-02 03:27:00")], + None, + None, + np.array(range(10)), + id="one_file_one_trace_full", + ), + ], +) +def test_mseed_file_read( + tmp_path: pytest.fixture, + streams: list[obspy.Stream], + files_begin: list[pd.Timestamp], + begin: pd.Timestamp | None, + end: pd.Timestamp | None, + expected_data: np.ndarray, +) -> None: + # WRITE MSEED FILES + for stream, begin in zip(streams, files_begin, strict=False): + stream.write( + tmp_path / f"{begin.strftime(TIMESTAMP_FORMATS_EXPORTED_FILES[1])}.mseed" + ) + + audio_files = [ + AudioFile(path, strptime_format=TIMESTAMP_FORMATS_EXPORTED_FILES[1]) + for path in tmp_path.glob("*.mseed") + ] + + assert audio_files[0].begin == begin + assert audio_files[0].sample_rate == streams[0].traces[0].meta.sampling_rate + + audio_data = AudioData.from_files(audio_files, begin=begin, end=end) + + assert np.array_equal(audio_data.get_value(), expected_data) + + @pytest.mark.parametrize( ("audio_files", "start", "stop", "expected"), [ From e80077b4321a45b69d9fb4d1211e647003e2944c Mon Sep 17 00:00:00 2001 From: Gautzilla <72027971+Gautzilla@users.noreply.github.com> Date: Thu, 25 Sep 2025 10:58:00 +0200 Subject: [PATCH 06/13] add more mseed AudioData tests --- tests/test_audio.py | 128 ++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 123 insertions(+), 5 deletions(-) diff --git a/tests/test_audio.py b/tests/test_audio.py index 05b30c03..ce5c1f72 100644 --- a/tests/test_audio.py +++ b/tests/test_audio.py @@ -208,7 +208,7 @@ def test_audio_file_read( obspy.Stream( obspy.Trace( data=np.array(range(10), dtype=np.int32), - header={"sampling_rate": 0.1}, + header={"sampling_rate": 10}, ), ), ], @@ -218,6 +218,117 @@ def test_audio_file_read( np.array(range(10)), id="one_file_one_trace_full", ), + pytest.param( + [ + obspy.Stream( + obspy.Trace( + data=np.array(range(10), dtype=np.int32), + header={"sampling_rate": 10}, + ), + ), + obspy.Stream( + obspy.Trace( + data=np.array(range(10, 20), dtype=np.int32), + header={"sampling_rate": 10}, + ), + ), + ], + [Timestamp("2002-04-02 03:27:00"), Timestamp("2002-04-02 03:27:01")], + None, + None, + np.array(range(20)), + id="multiple_files_one_trace_full", + ), + pytest.param( + [ + obspy.Stream( + [ + obspy.Trace( + data=np.array(range(10), dtype=np.int32), + header={"sampling_rate": 10}, + ), + obspy.Trace( + data=np.array(range(10, 20), dtype=np.int32), + header={"sampling_rate": 10}, + ), + ], + ), + ], + [Timestamp("2002-04-02 03:27:00")], + None, + None, + np.array(range(20)), + id="one_file_two_traces_full", + ), + pytest.param( + [ + obspy.Stream( + [ + obspy.Trace( + data=np.array(range(10), dtype=np.int32), + header={"sampling_rate": 10}, + ), + obspy.Trace( + data=np.array(range(10, 20), dtype=np.int32), + header={"sampling_rate": 10}, + ), + ], + ), + obspy.Stream( + obspy.Trace( + data=np.array(range(20, 30), dtype=np.int32), + header={"sampling_rate": 10}, + ), + ), + ], + [Timestamp("2002-04-02 03:27:00"), Timestamp("2002-04-02 03:27:02")], + None, + None, + np.array(range(30)), + id="multiple_files_multiple_traces_full", + ), + pytest.param( + [ + obspy.Stream( + obspy.Trace( + data=np.array(range(10), dtype=np.int32), + header={"sampling_rate": 10}, + ), + ), + ], + [Timestamp("2002-04-02 03:27:00")], + Timestamp("2002-04-02 03:27:00.23"), + Timestamp("2002-04-02 03:27:00.48"), + np.array(range(2, 4)), + id="one_file_one_trace_part", + ), + pytest.param( + [ + obspy.Stream( + [ + obspy.Trace( + data=np.array(range(10), dtype=np.int32), + header={"sampling_rate": 10}, + ), + obspy.Trace( + data=np.array(range(10, 20), dtype=np.int32), + header={"sampling_rate": 10}, + ), + ], + ), + obspy.Stream( + obspy.Trace( + data=np.array(range(20, 30), dtype=np.int32), + header={"sampling_rate": 10}, + ), + ), + ], + [Timestamp("2002-04-02 03:27:00"), Timestamp("2002-04-02 03:27:02")], + Timestamp("2002-04-02 03:27:00.85"), + Timestamp("2002-04-02 03:27:02.64"), + np.array(range(8, 26)), + id="multiple_files_multiple_traces_part", + ), ], ) def test_mseed_file_read( @@ -229,9 +340,10 @@ def test_mseed_file_read( expected_data: np.ndarray, ) -> None: # WRITE MSEED FILES - for stream, begin in zip(streams, files_begin, strict=False): + for stream, file_begin in zip(streams, files_begin, strict=False): stream.write( - tmp_path / f"{begin.strftime(TIMESTAMP_FORMATS_EXPORTED_FILES[1])}.mseed" + tmp_path + / f"{file_begin.strftime(TIMESTAMP_FORMATS_EXPORTED_FILES[1])}.mseed", ) audio_files = [ @@ -239,8 +351,14 @@ def test_mseed_file_read( for path in tmp_path.glob("*.mseed") ] - assert audio_files[0].begin == begin - assert audio_files[0].sample_rate == streams[0].traces[0].meta.sampling_rate + assert all( + audio_file.begin == file_begin + for audio_file, file_begin in zip(audio_files, files_begin, strict=False) + ) + assert all( + audio_file.sample_rate == stream.traces[0].meta.sampling_rate + for audio_file, stream in zip(audio_files, streams, strict=False) + ) audio_data = AudioData.from_files(audio_files, begin=begin, end=end) From b6e2d6085e348be8431a0b4ff36db5cac935a914 Mon Sep 17 00:00:00 2001 From: Gautzilla <72027971+Gautzilla@users.noreply.github.com> Date: Thu, 25 Sep 2025 11:24:53 +0200 Subject: [PATCH 07/13] sort audio_files in mseed file tests --- tests/test_audio.py | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) diff --git a/tests/test_audio.py b/tests/test_audio.py index ce5c1f72..1e5cacb9 100644 --- a/tests/test_audio.py +++ b/tests/test_audio.py @@ -346,18 +346,21 @@ def test_mseed_file_read( / f"{file_begin.strftime(TIMESTAMP_FORMATS_EXPORTED_FILES[1])}.mseed", ) - audio_files = [ - AudioFile(path, strptime_format=TIMESTAMP_FORMATS_EXPORTED_FILES[1]) - for path in tmp_path.glob("*.mseed") - ] + audio_files = sorted( + ( + AudioFile(path, strptime_format=TIMESTAMP_FORMATS_EXPORTED_FILES[1]) + for path in tmp_path.glob("*.mseed") + ), + key=lambda af: af.begin, + ) assert all( audio_file.begin == file_begin - for audio_file, file_begin in zip(audio_files, files_begin, strict=False) + for audio_file, file_begin in zip(audio_files, files_begin, strict=True) ) assert all( audio_file.sample_rate == stream.traces[0].meta.sampling_rate - for audio_file, stream in zip(audio_files, streams, strict=False) + for audio_file, stream in zip(audio_files, streams, strict=True) ) audio_data = AudioData.from_files(audio_files, begin=begin, end=end) From 780e384a1ca70f9c7d4b1af845f18590c29e11f0 Mon Sep 17 00:00:00 2001 From: Gautzilla <72027971+Gautzilla@users.noreply.github.com> Date: Thu, 25 Sep 2025 11:49:20 +0200 Subject: [PATCH 08/13] add mseed sample_rate error test --- tests/test_audio.py | 29 +++++++++++++++++++++++++++++ 1 file changed, 29 insertions(+) diff --git a/tests/test_audio.py b/tests/test_audio.py index 1e5cacb9..fcdb8eca 100644 --- a/tests/test_audio.py +++ b/tests/test_audio.py @@ -368,6 +368,35 @@ def test_mseed_file_read( assert np.array_equal(audio_data.get_value(), expected_data) +def test_inconsistent_mseed_sample_rate_error(tmp_path: pytest.fixture) -> None: + filename = ( + tmp_path + / f"{Timestamp('2002-04-02 03:27:00').strftime(TIMESTAMP_FORMATS_EXPORTED_FILES[1])}.mseed" + ) + + obspy.Stream( + [ + obspy.Trace( + data=np.array(range(10), dtype=np.int32), + header={"sampling_rate": 10}, + ), + obspy.Trace( + data=np.array(range(10, 20), dtype=np.int32), + header={"sampling_rate": 20}, + ), + ], + ).write(filename) + + with pytest.raises( + ValueError, + match="Audio file has inconsistent sampling rate.", + ) as e: + assert ( + AudioFile(filename, strptime_format=TIMESTAMP_FORMATS_EXPORTED_FILES[1]) + == e + ) + + @pytest.mark.parametrize( ("audio_files", "start", "stop", "expected"), [ From 1cf4557b704a085b00297dc220f01bf03422acd3 Mon Sep 17 00:00:00 2001 From: Gautzilla <72027971+Gautzilla@users.noreply.github.com> Date: Thu, 25 Sep 2025 11:51:11 +0200 Subject: [PATCH 09/13] add afm error test for start after stop request --- tests/test_audio_file_manager.py | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/tests/test_audio_file_manager.py b/tests/test_audio_file_manager.py index f1032163..341c5204 100644 --- a/tests/test_audio_file_manager.py +++ b/tests/test_audio_file_manager.py @@ -123,6 +123,19 @@ def test_read( ), id="out_of_bounds_stop_raises_error", ), + pytest.param( + { + "duration": 1, + "sample_rate": 48_000, + "nb_files": 1, + }, + (20_000, 10_000), + pytest.raises( + ValueError, + match="Start should be inferior to Stop.", + ), + id="start_after_stop_raises_error", + ), ], indirect=["audio_files"], ) From ceea97770cdfa47efc49cbc7835528240efd2448 Mon Sep 17 00:00:00 2001 From: Gautzilla Date: Fri, 19 Dec 2025 12:35:33 +0100 Subject: [PATCH 10/13] refactor audiofilemanager to isolate MSEED support --- pyproject.toml | 6 +- src/osekit/audio_backend/audio_backend.py | 49 ++++++ .../audio_backend/audio_file_manager.py | 104 +++++++++++ src/osekit/audio_backend/mseed_backend.py | 77 +++++++++ src/osekit/audio_backend/soundfile_backend.py | 82 +++++++++ src/osekit/core_api/__init__.py | 2 +- src/osekit/core_api/audio_file_manager.py | 163 ------------------ tests/conftest.py | 8 +- tests/test_audio.py | 21 ++- tests/test_audio_file_manager.py | 27 +-- uv.lock | 103 ----------- 11 files changed, 349 insertions(+), 293 deletions(-) create mode 100644 src/osekit/audio_backend/audio_backend.py create mode 100644 src/osekit/audio_backend/audio_file_manager.py create mode 100644 src/osekit/audio_backend/mseed_backend.py create mode 100644 src/osekit/audio_backend/soundfile_backend.py delete mode 100644 src/osekit/core_api/audio_file_manager.py diff --git a/pyproject.toml b/pyproject.toml index 1a89766f..caf17854 100755 --- a/pyproject.toml +++ b/pyproject.toml @@ -11,7 +11,6 @@ dependencies = [ "matplotlib>=3.10.7", "notebook>=7.4.4", "numpy>=2.2.6", - "obspy>=1.4.2", "pandas>=2.2.3", "pytest>=8.3.5", "pyyaml>=6.0.2", @@ -30,6 +29,11 @@ classifiers = [ [project.scripts] OSEkit = "OSmOSE:main" +[project.optional-dependencies] +mseed = [ + "obspy", +] + [build-system] requires = ["hatchling"] build-backend = "hatchling.build" diff --git a/src/osekit/audio_backend/audio_backend.py b/src/osekit/audio_backend/audio_backend.py new file mode 100644 index 00000000..7aa3cf58 --- /dev/null +++ b/src/osekit/audio_backend/audio_backend.py @@ -0,0 +1,49 @@ +from os import PathLike +from typing import Protocol + +import numpy as np + + +class AudioBackend(Protocol): + def info(self, path: PathLike | str) -> tuple[int, int, int]: + """Return the sample rate, number of frames and channels of the audio file. + + Parameters + ---------- + path: PathLike | str + Path to the audio file. + + Returns + ------- + tuple[int,int,int]: + Sample rate, number of frames and channels of the audio file. + + """ + ... + + def read(self, path: PathLike | str, start: int, stop: int) -> np.ndarray: + """Read the content of an audio file. + + If the audio file is not the current opened file, + the current opened file is switched. + + Parameters + ---------- + path: PathLike | str + Path to the audio file. + start: int + First frame to read. + stop: int + Frame after the last frame to read. + + Returns + ------- + np.ndarray: + A (channel * frames) array containing the audio data. + + """ + ... + + def close(self) -> None: + """Close the currently opened file.""" + ... diff --git a/src/osekit/audio_backend/audio_file_manager.py b/src/osekit/audio_backend/audio_file_manager.py new file mode 100644 index 00000000..86de6a7c --- /dev/null +++ b/src/osekit/audio_backend/audio_file_manager.py @@ -0,0 +1,104 @@ +"""Audio File Manager which keeps an audio file open until a request in another file is made. + +This workflow avoids closing/opening a same file repeatedly. +""" + +from __future__ import annotations + +from pathlib import Path +from typing import TYPE_CHECKING + +from osekit.audio_backend.mseed_backend import MSeedBackend +from osekit.audio_backend.soundfile_backend import SoundFileBackend + +if TYPE_CHECKING: + from os import PathLike + + import numpy as np + + +class AudioFileManager: + """Audio File Manager which keeps an audio file open until a request in another file is made.""" + + def __init__(self) -> None: + """Initialize an audio file manager.""" + self._soundfile = SoundFileBackend() + self._mseed: MSeedBackend | None = None + + def close(self) -> None: + """Close the currently opened file.""" + self._soundfile.close() + if self._mseed: + self._mseed.close() + + def _backend(self, path: PathLike | str) -> SoundFileBackend | MSeedBackend: + suffix = Path(path).suffix.lower() + + if suffix == ".mseed": + if self._mseed is None: + self._mseed = MSeedBackend() + return self._mseed + + return self._soundfile + + def info(self, path: PathLike | str) -> tuple[int, int, int]: + """Return the sample rate, number of frames and channels of the audio file. + + Parameters + ---------- + path: PathLike | str + Path to the audio file. + + Returns + ------- + tuple[int,int,int]: + Sample rate, number of frames and channels of the audio file. + + """ + return self._backend(path).info(path) + + def read( + self, + path: PathLike | str, + start: int = 0, + stop: int | None = None, + ) -> np.ndarray: + """Read the content of an audio file. + + If the audio file is not the current opened file, + the current opened file is switched. + + Parameters + ---------- + path: PathLike | str + Path to the audio file. + start: int + First frame to read. + stop: int | None + Frame after the last frame to read. + + Returns + ------- + np.ndarray: + A (channel * frames) array containing the audio data. + + """ + _, frames, _ = self.info(path) + + if stop is None: + stop = frames + + if stop is None: + stop = frames + + if not 0 <= start < frames: + msg = "Start should be between 0 and the last frame of the audio file." + raise ValueError(msg) + if not 0 <= stop <= frames: + msg = "Stop should be between 0 and the last frame of the audio file." + raise ValueError(msg) + if start > stop: + msg = "Start should be inferior to Stop." + raise ValueError(msg) + + return self._backend(path).read(path=path, start=start, stop=stop) diff --git a/src/osekit/audio_backend/mseed_backend.py b/src/osekit/audio_backend/mseed_backend.py new file mode 100644 index 00000000..f91f09f2 --- /dev/null +++ b/src/osekit/audio_backend/mseed_backend.py @@ -0,0 +1,77 @@ +from os import PathLike + +import numpy as np + + +class MSeedBackend: + def __init__(self) -> None: + try: + import obspy # noqa: F401, PLC0415 + except ImportError as e: + msg = "MSEED support requires the optional dependency 'obspy' " + "Install with: pip install osekit[mseed]. " + "If you're on windows and don't use conda, may the force be with you." + raise ImportError(msg) from e + + def close(self) -> None: + """Close the currently opened file. No use in MSEED files.""" + + def info(self, path: PathLike | str) -> tuple[int, int, int]: + """Return the sample rate, number of frames and channels of the MSEED file. + + Parameters + ---------- + path: PathLike | str + Path to the audio file. + + Returns + ------- + tuple[int,int,int]: + Sample rate, number of frames and channels of the MSEED file. + + """ + import obspy # type: ignore[import-not-found] # noqa: PLC0415 + + metadata = obspy.read(pathname_or_url=path, headonly=True) + sample_rate = {trace.meta.sampling_rate for trace in metadata.traces} + if len(sample_rate) != 1: + msg = "Inconsistent sampling rates in MSEED file" + raise ValueError(msg) + + frames = sum(trace.meta.npts for trace in metadata.traces) + return ( + int(sample_rate.pop()), + frames, + 1, + ) + + def read( + self, + path: PathLike | str, + start: int = 0, + stop: int | None = None, + ) -> np.ndarray: + """Read the content of a MSEED file. + + Parameters + ---------- + path: PathLike | str + Path to the audio file. + start: int + First frame to read. + stop: int + Frame after the last frame to read. + + Returns + ------- + np.ndarray: + A (channel * frames) array containing the MSEED data. + + """ + import obspy # type: ignore[import-not-found] # noqa: PLC0415 + + file_content = obspy.read(path) + file_content.merge(method=1, fill_value=0) + + data = np.concatenate([trace.data for trace in file_content]) + return data[start:stop] diff --git a/src/osekit/audio_backend/soundfile_backend.py b/src/osekit/audio_backend/soundfile_backend.py new file mode 100644 index 00000000..897d542d --- /dev/null +++ b/src/osekit/audio_backend/soundfile_backend.py @@ -0,0 +1,82 @@ +from os import PathLike + +import numpy as np +import soundfile as sf + + +class SoundFileBackend: + def __init__(self) -> None: + """Instantiate a SoundFileBackend.""" + self._file: sf.SoundFile | None = None + + def close(self) -> None: + """Close the currently opened file.""" + if self._file is None: + return + self._file.close() + self._file = None + + def info(self, path: PathLike | str) -> tuple[int, int, int]: + """Return the sample rate, number of frames and channels of the audio file. + + Parameters + ---------- + path: PathLike | str + Path to the audio file. + + Returns + ------- + tuple[int,int,int]: + Sample rate, number of frames and channels of the audio file. + + """ + self._switch(path) + return ( + self._file.samplerate, + self._file.frames, + self._file.channels, + ) + + def read( + self, + path: PathLike | str, + start: int = 0, + stop: int | None = None, + ) -> np.ndarray: + """Read the content of an audio file. + + If the audio file is not the current opened file, + the current opened file is switched. + + Parameters + ---------- + path: PathLike | str + Path to the audio file. + start: int + First frame to read. + stop: int + Frame after the last frame to read. + + Returns + ------- + np.ndarray: + A (channel * frames) array containing the audio data. + + """ + self._switch(path) + self._file.seek(start) + return self._file.read(stop - start) + + def _close(self) -> None: + if self._file is None: + return + self._file.close() + self._file = None + + def _open(self, path: PathLike | str) -> None: + self._file = sf.SoundFile(path, "r") + + def _switch(self, path: PathLike | str) -> None: + if self._file is None or self._file.name != str(path): + self._close() + self._open(path) diff --git a/src/osekit/core_api/__init__.py b/src/osekit/core_api/__init__.py index e0c5f878..fbe44cba 100644 --- a/src/osekit/core_api/__init__.py +++ b/src/osekit/core_api/__init__.py @@ -1,3 +1,3 @@ -from osekit.core_api.audio_file_manager import AudioFileManager +from osekit.audio_backend.audio_file_manager import AudioFileManager audio_file_manager = AudioFileManager() diff --git a/src/osekit/core_api/audio_file_manager.py b/src/osekit/core_api/audio_file_manager.py deleted file mode 100644 index 05c9d6cb..00000000 --- a/src/osekit/core_api/audio_file_manager.py +++ /dev/null @@ -1,163 +0,0 @@ -"""Audio File Manager which keeps an audio file open until a request in another file is made. - -This workflow avoids closing/opening a same file repeatedly. -""" - -from __future__ import annotations - -from pathlib import Path -from typing import TYPE_CHECKING - -import numpy as np -import obspy -import soundfile as sf - -if TYPE_CHECKING: - from os import PathLike - - -class AudioFileManager: - """Audio File Manager which keeps an audio file open until a request in another file is made.""" - - def __init__(self) -> None: - """Initialize an audio file manager.""" - self.opened_file = None - - def close(self) -> None: - """Close the currently opened file.""" - if self.opened_file is None: - return - self.opened_file.close() - self.opened_file = None - - def _open(self, path: PathLike | str) -> None: - self.opened_file = sf.SoundFile(path, "r") - - def _switch(self, path: PathLike | str) -> None: - if self.opened_file is None: - self._open(path) - if self.opened_file.name == str(path): - return - self.close() - self._open(path) - - @staticmethod - def _check_boudaries(start: int, stop: int, frames: int) -> None: - if not 0 <= start < frames: - msg = "Start should be between 0 and the last frame of the audio file." - raise ValueError(msg) - if not 0 <= stop <= frames: - msg = "Stop should be between 0 and the last frame of the audio file." - raise ValueError(msg) - if start > stop: - msg = "Start should be inferior to Stop." - raise ValueError(msg) - - @staticmethod - def _read_mseed(path: PathLike | str, start: int, stop: int) -> np.ndarray: - """Read the content of a mseed file between the start and stop frames. - - Parameters - ---------- - path: PathLike | str - Path to the mseed file. - start: int - First frame to read. - stop: int - Frame after the last frame to read. - - Returns - ------- - np.ndarray: - A (stop-start)-long array containing the mseed audio data. - - """ - return np.concat([trace.data for trace in obspy.read(path).traces])[start:stop] - - def read( - self, - path: PathLike | str, - start: int = 0, - stop: int | None = None, - ) -> np.ndarray: - """Read the content of an audio file. - - If the audio file is not the current opened file, - the current opened file is switched. - - Parameters - ---------- - path: PathLike | str - Path to the audio file. - start: int - First frame to read. - stop: int - Frame after the last frame to read. - - Returns - ------- - np.ndarray: - A (channel * frames) array containing the audio data. - - """ - _, frames, _ = self.info(path) - if stop is None: - stop = frames - self._check_boudaries(start=start, stop=stop, frames=frames) - - if Path(path).suffix == ".mseed": - return self._read_mseed(path=path, start=start, stop=stop) - - self.opened_file.seek(start) - return self.opened_file.read(stop - start) - - def info(self, path: PathLike | str) -> tuple[int, int, int]: - """Return the sample rate, number of frames and channels of the audio file. - - Parameters - ---------- - path: PathLike | str - Path to the audio file. - - Returns - ------- - tuple[int,int,int]: - Sample rate, number of frames and channels of the audio file. - - """ - if Path(path).suffix == ".mseed": - return self.mseed_info(path) - - self._switch(path) - return ( - self.opened_file.samplerate, - self.opened_file.frames, - self.opened_file.channels, - ) - - @staticmethod - def mseed_info(path: PathLike | str) -> tuple[int, int, int]: - """Return the sample rate, number of frames and channels of the mseed file. - - Parameters - ---------- - path: PathLike | str - Path to the mseed file. - - Returns - ------- - tuple[int,int,int]: - Sample rate, number of frames and channels of the mseed file. - - """ - metadata = obspy.read(pathname_or_url=path, headonly=True) - sample_rate = set(trace.meta.sampling_rate for trace in metadata.traces) - if len(sample_rate) != 1: - raise ValueError("Audio file has inconsistent sampling rate.") - sample_rate = sample_rate.pop() - frames = sum(trace.meta.npts for trace in metadata.traces) - return ( - sample_rate, - frames, - 1, - ) diff --git a/tests/conftest.py b/tests/conftest.py index 522a0bd8..367f299b 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -14,11 +14,11 @@ from pandas import Timestamp from osekit import config +from osekit.audio_backend.soundfile_backend import SoundFileBackend from osekit.config import ( TIMESTAMP_FORMAT_EXPORTED_FILES_LOCALIZED, TIMESTAMP_FORMAT_EXPORTED_FILES_UNLOCALIZED, ) -from osekit.core_api import AudioFileManager from osekit.core_api.audio_data import AudioData from osekit.core_api.audio_file import AudioFile from osekit.core_api.base_dataset import BaseDataset @@ -159,13 +159,13 @@ def patch_afm_open(monkeypatch: pytest.MonkeyPatch) -> list[Path]: """Mock the AudioFileManager._open method in order to track the file openings.""" opened_files = [] - open_func = AudioFileManager._open + open_func = SoundFileBackend._open - def mock_open(self: AudioFileManager, path: Path) -> None: + def mock_open(self: SoundFileBackend, path: Path) -> None: opened_files.append(path) open_func(self, path) - monkeypatch.setattr(AudioFileManager, "_open", mock_open) + monkeypatch.setattr(SoundFileBackend, "_open", mock_open) return opened_files diff --git a/tests/test_audio.py b/tests/test_audio.py index 1da4f773..4017e696 100644 --- a/tests/test_audio.py +++ b/tests/test_audio.py @@ -6,7 +6,6 @@ from typing import Literal import numpy as np -import obspy import pandas as pd import pytest import soundfile as sf @@ -16,7 +15,6 @@ from osekit.config import ( TIMESTAMP_FORMAT_EXPORTED_FILES_LOCALIZED, TIMESTAMP_FORMAT_EXPORTED_FILES_UNLOCALIZED, - TIMESTAMP_FORMATS_EXPORTED_FILES, resample_quality_settings, ) from osekit.core_api import AudioFileManager @@ -256,6 +254,7 @@ def init_patch(self: AudioFile, *args: list, **kwargs: dict) -> None: ) +""" @pytest.mark.parametrize( ("streams", "files_begin", "begin", "end", "expected_data"), [ @@ -422,8 +421,9 @@ def test_mseed_file_read( audio_data = AudioData.from_files(audio_files, begin=begin, end=end) assert np.array_equal(audio_data.get_value(), expected_data) +""" - +""" def test_inconsistent_mseed_sample_rate_error(tmp_path: pytest.fixture) -> None: filename = ( tmp_path @@ -451,6 +451,7 @@ def test_inconsistent_mseed_sample_rate_error(tmp_path: pytest.fixture) -> None: AudioFile(filename, strptime_format=TIMESTAMP_FORMATS_EXPORTED_FILES[1]) == e ) +""" @pytest.mark.parametrize( @@ -2070,32 +2071,34 @@ def test_move_audio_file( old_path = str(af.path) af_name = af.path.name + sf_back = afm._soundfile + # Moving file without opening it first af.move(destination_folder) assert (destination_folder / af_name).exists() assert not Path(old_path).exists() - assert afm.opened_file is None + assert sf_back._file is None # Accessing the file at the new path ad.get_value() - assert afm.opened_file is not None - assert afm.opened_file.name == str(af.path) + assert sf_back._file is not None + assert sf_back._file.name == str(af.path) # Moving it back after opening it in the afm # afm should close the file to allow the moving af.move(tmp_path) - assert afm.opened_file is None + assert sf_back._file is None assert not (destination_folder / af_name).exists() assert Path(old_path).exists() # Reading the file again ad.get_value() - assert afm.opened_file is not None - assert afm.opened_file.name == str(af.path) + assert sf_back._file is not None + assert sf_back._file.name == str(af.path) @pytest.mark.parametrize( diff --git a/tests/test_audio_file_manager.py b/tests/test_audio_file_manager.py index 44f9fe87..01c0b3b6 100644 --- a/tests/test_audio_file_manager.py +++ b/tests/test_audio_file_manager.py @@ -6,7 +6,7 @@ import numpy as np import pytest -from osekit.core_api.audio_file_manager import AudioFileManager +from osekit.audio_backend.audio_file_manager import AudioFileManager from osekit.utils.audio_utils import generate_sample_audio if TYPE_CHECKING: @@ -83,7 +83,7 @@ def test_read( (-10, None), pytest.raises( ValueError, - match="Start should be between 0 and the last frame of the audio file.", + match=r"Start should be between 0 and the last frame of the audio file.", ), id="negative_start_raises_error", ), @@ -96,7 +96,7 @@ def test_read( (50_000, None), pytest.raises( ValueError, - match="Start should be between 0 and the last frame of the audio file.", + match=r"Start should be between 0 and the last frame of the audio file.", ), id="out_of_bounds_start_raises_error", ), @@ -109,7 +109,7 @@ def test_read( (None, -10), pytest.raises( ValueError, - match="Stop should be between 0 and the last frame of the audio file.", + match=r"Stop should be between 0 and the last frame of the audio file.", ), id="negative_stop_raises_error", ), @@ -122,7 +122,7 @@ def test_read( (None, 50_000), pytest.raises( ValueError, - match="Stop should be between 0 and the last frame of the audio file.", + match=r"Stop should be between 0 and the last frame of the audio file.", ), id="out_of_bounds_stop_raises_error", ), @@ -135,7 +135,7 @@ def test_read( (20_000, 10_000), pytest.raises( ValueError, - match="Start should be inferior to Stop.", + match=r"Start should be inferior to Stop.", ), id="start_after_stop_raises_error", ), @@ -208,12 +208,13 @@ def test_switch( expected_opened_files: list[int], ) -> None: afm = AudioFileManager() + sf_back = afm._soundfile audio_files, _ = audio_files audio_files = [af.path for af in audio_files] for file in file_openings: afm.read(path=audio_files[file]) assert [audio_files.index(f) for f in patch_afm_open] == expected_opened_files - assert audio_files.index(Path(afm.opened_file.name)) == file_openings[-1] + assert audio_files.index(Path(sf_back._file.name)) == file_openings[-1] @pytest.mark.parametrize( @@ -232,13 +233,14 @@ def test_switch( ) def test_close(audio_files: tuple[list[AudioFile], pytest.fixtures.Subrequest]) -> None: afm = AudioFileManager() - assert afm.opened_file is None + sf_back = afm._soundfile + assert sf_back._file is None audio_files, _ = audio_files afm.read(audio_files[0].path) - assert afm.opened_file is not None - assert Path(afm.opened_file.name) == audio_files[0].path + assert sf_back._file is not None + assert Path(sf_back._file.name) == audio_files[0].path afm.close() - assert afm.opened_file is None + assert sf_back._file is None @pytest.mark.parametrize( @@ -257,9 +259,10 @@ def test_close(audio_files: tuple[list[AudioFile], pytest.fixtures.Subrequest]) ) def test_info(audio_files: tuple[list[AudioFile], pytest.fixtures.Subrequest]) -> None: afm = AudioFileManager() + sf_back = afm._soundfile audio_files, request = audio_files for file in audio_files: - assert afm.opened_file is None or Path(afm.opened_file.name) != file.path.name + assert sf_back._file is None or Path(sf_back._file.name) != file.path.name sample_rate, frames, channels = afm.info(file.path) assert request.param["sample_rate"] == sample_rate assert request.param["duration"] * request.param["sample_rate"] == frames diff --git a/uv.lock b/uv.lock index 9dbfcf39..b8673c19 100644 --- a/uv.lock +++ b/uv.lock @@ -1280,86 +1280,6 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/a8/3e/1c6b43277de64fc3c0333b0e72ab7b52ddaaea205210d60d9b9f83c3d0c7/lark-1.3.0-py3-none-any.whl", hash = "sha256:80661f261fb2584a9828a097a2432efd575af27d20be0fd35d17f0fe37253831", size = 113002, upload-time = "2025-09-22T13:45:03.747Z" }, ] -[[package]] -name = "lxml" -version = "6.0.2" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/aa/88/262177de60548e5a2bfc46ad28232c9e9cbde697bd94132aeb80364675cb/lxml-6.0.2.tar.gz", hash = "sha256:cd79f3367bd74b317dda655dc8fcfa304d9eb6e4fb06b7168c5cf27f96e0cd62", size = 4073426, upload-time = "2025-09-22T04:04:59.287Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/f3/c8/8ff2bc6b920c84355146cd1ab7d181bc543b89241cfb1ebee824a7c81457/lxml-6.0.2-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:a59f5448ba2ceccd06995c95ea59a7674a10de0810f2ce90c9006f3cbc044456", size = 8661887, upload-time = "2025-09-22T04:01:17.265Z" }, - { url = "https://files.pythonhosted.org/packages/37/6f/9aae1008083bb501ef63284220ce81638332f9ccbfa53765b2b7502203cf/lxml-6.0.2-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:e8113639f3296706fbac34a30813929e29247718e88173ad849f57ca59754924", size = 4667818, upload-time = "2025-09-22T04:01:19.688Z" }, - { url = "https://files.pythonhosted.org/packages/f1/ca/31fb37f99f37f1536c133476674c10b577e409c0a624384147653e38baf2/lxml-6.0.2-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:a8bef9b9825fa8bc816a6e641bb67219489229ebc648be422af695f6e7a4fa7f", size = 4950807, upload-time = "2025-09-22T04:01:21.487Z" }, - { url = "https://files.pythonhosted.org/packages/da/87/f6cb9442e4bada8aab5ae7e1046264f62fdbeaa6e3f6211b93f4c0dd97f1/lxml-6.0.2-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:65ea18d710fd14e0186c2f973dc60bb52039a275f82d3c44a0e42b43440ea534", size = 5109179, upload-time = "2025-09-22T04:01:23.32Z" }, - { url = "https://files.pythonhosted.org/packages/c8/20/a7760713e65888db79bbae4f6146a6ae5c04e4a204a3c48896c408cd6ed2/lxml-6.0.2-cp312-cp312-manylinux_2_26_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:c371aa98126a0d4c739ca93ceffa0fd7a5d732e3ac66a46e74339acd4d334564", size = 5023044, upload-time = "2025-09-22T04:01:25.118Z" }, - { url = "https://files.pythonhosted.org/packages/a2/b0/7e64e0460fcb36471899f75831509098f3fd7cd02a3833ac517433cb4f8f/lxml-6.0.2-cp312-cp312-manylinux_2_26_i686.manylinux_2_28_i686.whl", hash = "sha256:700efd30c0fa1a3581d80a748157397559396090a51d306ea59a70020223d16f", size = 5359685, upload-time = "2025-09-22T04:01:27.398Z" }, - { url = "https://files.pythonhosted.org/packages/b9/e1/e5df362e9ca4e2f48ed6411bd4b3a0ae737cc842e96877f5bf9428055ab4/lxml-6.0.2-cp312-cp312-manylinux_2_26_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:c33e66d44fe60e72397b487ee92e01da0d09ba2d66df8eae42d77b6d06e5eba0", size = 5654127, upload-time = "2025-09-22T04:01:29.629Z" }, - { url = "https://files.pythonhosted.org/packages/c6/d1/232b3309a02d60f11e71857778bfcd4acbdb86c07db8260caf7d008b08f8/lxml-6.0.2-cp312-cp312-manylinux_2_26_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:90a345bbeaf9d0587a3aaffb7006aa39ccb6ff0e96a57286c0cb2fd1520ea192", size = 5253958, upload-time = "2025-09-22T04:01:31.535Z" }, - { url = "https://files.pythonhosted.org/packages/35/35/d955a070994725c4f7d80583a96cab9c107c57a125b20bb5f708fe941011/lxml-6.0.2-cp312-cp312-manylinux_2_31_armv7l.whl", hash = "sha256:064fdadaf7a21af3ed1dcaa106b854077fbeada827c18f72aec9346847cd65d0", size = 4711541, upload-time = "2025-09-22T04:01:33.801Z" }, - { url = "https://files.pythonhosted.org/packages/1e/be/667d17363b38a78c4bd63cfd4b4632029fd68d2c2dc81f25ce9eb5224dd5/lxml-6.0.2-cp312-cp312-manylinux_2_38_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:fbc74f42c3525ac4ffa4b89cbdd00057b6196bcefe8bce794abd42d33a018092", size = 5267426, upload-time = "2025-09-22T04:01:35.639Z" }, - { url = "https://files.pythonhosted.org/packages/ea/47/62c70aa4a1c26569bc958c9ca86af2bb4e1f614e8c04fb2989833874f7ae/lxml-6.0.2-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:6ddff43f702905a4e32bc24f3f2e2edfe0f8fde3277d481bffb709a4cced7a1f", size = 5064917, upload-time = "2025-09-22T04:01:37.448Z" }, - { url = "https://files.pythonhosted.org/packages/bd/55/6ceddaca353ebd0f1908ef712c597f8570cc9c58130dbb89903198e441fd/lxml-6.0.2-cp312-cp312-musllinux_1_2_armv7l.whl", hash = "sha256:6da5185951d72e6f5352166e3da7b0dc27aa70bd1090b0eb3f7f7212b53f1bb8", size = 4788795, upload-time = "2025-09-22T04:01:39.165Z" }, - { url = "https://files.pythonhosted.org/packages/cf/e8/fd63e15da5e3fd4c2146f8bbb3c14e94ab850589beab88e547b2dbce22e1/lxml-6.0.2-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:57a86e1ebb4020a38d295c04fc79603c7899e0df71588043eb218722dabc087f", size = 5676759, upload-time = "2025-09-22T04:01:41.506Z" }, - { url = "https://files.pythonhosted.org/packages/76/47/b3ec58dc5c374697f5ba37412cd2728f427d056315d124dd4b61da381877/lxml-6.0.2-cp312-cp312-musllinux_1_2_riscv64.whl", hash = "sha256:2047d8234fe735ab77802ce5f2297e410ff40f5238aec569ad7c8e163d7b19a6", size = 5255666, upload-time = "2025-09-22T04:01:43.363Z" }, - { url = "https://files.pythonhosted.org/packages/19/93/03ba725df4c3d72afd9596eef4a37a837ce8e4806010569bedfcd2cb68fd/lxml-6.0.2-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:6f91fd2b2ea15a6800c8e24418c0775a1694eefc011392da73bc6cef2623b322", size = 5277989, upload-time = "2025-09-22T04:01:45.215Z" }, - { url = "https://files.pythonhosted.org/packages/c6/80/c06de80bfce881d0ad738576f243911fccf992687ae09fd80b734712b39c/lxml-6.0.2-cp312-cp312-win32.whl", hash = "sha256:3ae2ce7d6fedfb3414a2b6c5e20b249c4c607f72cb8d2bb7cc9c6ec7c6f4e849", size = 3611456, upload-time = "2025-09-22T04:01:48.243Z" }, - { url = "https://files.pythonhosted.org/packages/f7/d7/0cdfb6c3e30893463fb3d1e52bc5f5f99684a03c29a0b6b605cfae879cd5/lxml-6.0.2-cp312-cp312-win_amd64.whl", hash = "sha256:72c87e5ee4e58a8354fb9c7c84cbf95a1c8236c127a5d1b7683f04bed8361e1f", size = 4011793, upload-time = "2025-09-22T04:01:50.042Z" }, - { url = "https://files.pythonhosted.org/packages/ea/7b/93c73c67db235931527301ed3785f849c78991e2e34f3fd9a6663ffda4c5/lxml-6.0.2-cp312-cp312-win_arm64.whl", hash = "sha256:61cb10eeb95570153e0c0e554f58df92ecf5109f75eacad4a95baa709e26c3d6", size = 3672836, upload-time = "2025-09-22T04:01:52.145Z" }, - { url = "https://files.pythonhosted.org/packages/53/fd/4e8f0540608977aea078bf6d79f128e0e2c2bba8af1acf775c30baa70460/lxml-6.0.2-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:9b33d21594afab46f37ae58dfadd06636f154923c4e8a4d754b0127554eb2e77", size = 8648494, upload-time = "2025-09-22T04:01:54.242Z" }, - { url = "https://files.pythonhosted.org/packages/5d/f4/2a94a3d3dfd6c6b433501b8d470a1960a20ecce93245cf2db1706adf6c19/lxml-6.0.2-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:6c8963287d7a4c5c9a432ff487c52e9c5618667179c18a204bdedb27310f022f", size = 4661146, upload-time = "2025-09-22T04:01:56.282Z" }, - { url = "https://files.pythonhosted.org/packages/25/2e/4efa677fa6b322013035d38016f6ae859d06cac67437ca7dc708a6af7028/lxml-6.0.2-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:1941354d92699fb5ffe6ed7b32f9649e43c2feb4b97205f75866f7d21aa91452", size = 4946932, upload-time = "2025-09-22T04:01:58.989Z" }, - { url = "https://files.pythonhosted.org/packages/ce/0f/526e78a6d38d109fdbaa5049c62e1d32fdd70c75fb61c4eadf3045d3d124/lxml-6.0.2-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:bb2f6ca0ae2d983ded09357b84af659c954722bbf04dea98030064996d156048", size = 5100060, upload-time = "2025-09-22T04:02:00.812Z" }, - { url = "https://files.pythonhosted.org/packages/81/76/99de58d81fa702cc0ea7edae4f4640416c2062813a00ff24bd70ac1d9c9b/lxml-6.0.2-cp313-cp313-manylinux_2_26_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:eb2a12d704f180a902d7fa778c6d71f36ceb7b0d317f34cdc76a5d05aa1dd1df", size = 5019000, upload-time = "2025-09-22T04:02:02.671Z" }, - { url = "https://files.pythonhosted.org/packages/b5/35/9e57d25482bc9a9882cb0037fdb9cc18f4b79d85df94fa9d2a89562f1d25/lxml-6.0.2-cp313-cp313-manylinux_2_26_i686.manylinux_2_28_i686.whl", hash = "sha256:6ec0e3f745021bfed19c456647f0298d60a24c9ff86d9d051f52b509663feeb1", size = 5348496, upload-time = "2025-09-22T04:02:04.904Z" }, - { url = "https://files.pythonhosted.org/packages/a6/8e/cb99bd0b83ccc3e8f0f528e9aa1f7a9965dfec08c617070c5db8d63a87ce/lxml-6.0.2-cp313-cp313-manylinux_2_26_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:846ae9a12d54e368933b9759052d6206a9e8b250291109c48e350c1f1f49d916", size = 5643779, upload-time = "2025-09-22T04:02:06.689Z" }, - { url = "https://files.pythonhosted.org/packages/d0/34/9e591954939276bb679b73773836c6684c22e56d05980e31d52a9a8deb18/lxml-6.0.2-cp313-cp313-manylinux_2_26_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:ef9266d2aa545d7374938fb5c484531ef5a2ec7f2d573e62f8ce722c735685fd", size = 5244072, upload-time = "2025-09-22T04:02:08.587Z" }, - { url = "https://files.pythonhosted.org/packages/8d/27/b29ff065f9aaca443ee377aff699714fcbffb371b4fce5ac4ca759e436d5/lxml-6.0.2-cp313-cp313-manylinux_2_31_armv7l.whl", hash = "sha256:4077b7c79f31755df33b795dc12119cb557a0106bfdab0d2c2d97bd3cf3dffa6", size = 4718675, upload-time = "2025-09-22T04:02:10.783Z" }, - { url = "https://files.pythonhosted.org/packages/2b/9f/f756f9c2cd27caa1a6ef8c32ae47aadea697f5c2c6d07b0dae133c244fbe/lxml-6.0.2-cp313-cp313-manylinux_2_38_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:a7c5d5e5f1081955358533be077166ee97ed2571d6a66bdba6ec2f609a715d1a", size = 5255171, upload-time = "2025-09-22T04:02:12.631Z" }, - { url = "https://files.pythonhosted.org/packages/61/46/bb85ea42d2cb1bd8395484fd72f38e3389611aa496ac7772da9205bbda0e/lxml-6.0.2-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:8f8d0cbd0674ee89863a523e6994ac25fd5be9c8486acfc3e5ccea679bad2679", size = 5057175, upload-time = "2025-09-22T04:02:14.718Z" }, - { url = "https://files.pythonhosted.org/packages/95/0c/443fc476dcc8e41577f0af70458c50fe299a97bb6b7505bb1ae09aa7f9ac/lxml-6.0.2-cp313-cp313-musllinux_1_2_armv7l.whl", hash = "sha256:2cbcbf6d6e924c28f04a43f3b6f6e272312a090f269eff68a2982e13e5d57659", size = 4785688, upload-time = "2025-09-22T04:02:16.957Z" }, - { url = "https://files.pythonhosted.org/packages/48/78/6ef0b359d45bb9697bc5a626e1992fa5d27aa3f8004b137b2314793b50a0/lxml-6.0.2-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:dfb874cfa53340009af6bdd7e54ebc0d21012a60a4e65d927c2e477112e63484", size = 5660655, upload-time = "2025-09-22T04:02:18.815Z" }, - { url = "https://files.pythonhosted.org/packages/ff/ea/e1d33808f386bc1339d08c0dcada6e4712d4ed8e93fcad5f057070b7988a/lxml-6.0.2-cp313-cp313-musllinux_1_2_riscv64.whl", hash = "sha256:fb8dae0b6b8b7f9e96c26fdd8121522ce5de9bb5538010870bd538683d30e9a2", size = 5247695, upload-time = "2025-09-22T04:02:20.593Z" }, - { url = "https://files.pythonhosted.org/packages/4f/47/eba75dfd8183673725255247a603b4ad606f4ae657b60c6c145b381697da/lxml-6.0.2-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:358d9adae670b63e95bc59747c72f4dc97c9ec58881d4627fe0120da0f90d314", size = 5269841, upload-time = "2025-09-22T04:02:22.489Z" }, - { url = "https://files.pythonhosted.org/packages/76/04/5c5e2b8577bc936e219becb2e98cdb1aca14a4921a12995b9d0c523502ae/lxml-6.0.2-cp313-cp313-win32.whl", hash = "sha256:e8cd2415f372e7e5a789d743d133ae474290a90b9023197fd78f32e2dc6873e2", size = 3610700, upload-time = "2025-09-22T04:02:24.465Z" }, - { url = "https://files.pythonhosted.org/packages/fe/0a/4643ccc6bb8b143e9f9640aa54e38255f9d3b45feb2cbe7ae2ca47e8782e/lxml-6.0.2-cp313-cp313-win_amd64.whl", hash = "sha256:b30d46379644fbfc3ab81f8f82ae4de55179414651f110a1514f0b1f8f6cb2d7", size = 4010347, upload-time = "2025-09-22T04:02:26.286Z" }, - { url = "https://files.pythonhosted.org/packages/31/ef/dcf1d29c3f530577f61e5fe2f1bd72929acf779953668a8a47a479ae6f26/lxml-6.0.2-cp313-cp313-win_arm64.whl", hash = "sha256:13dcecc9946dca97b11b7c40d29fba63b55ab4170d3c0cf8c0c164343b9bfdcf", size = 3671248, upload-time = "2025-09-22T04:02:27.918Z" }, - { url = "https://files.pythonhosted.org/packages/03/15/d4a377b385ab693ce97b472fe0c77c2b16ec79590e688b3ccc71fba19884/lxml-6.0.2-cp314-cp314-macosx_10_13_universal2.whl", hash = "sha256:b0c732aa23de8f8aec23f4b580d1e52905ef468afb4abeafd3fec77042abb6fe", size = 8659801, upload-time = "2025-09-22T04:02:30.113Z" }, - { url = "https://files.pythonhosted.org/packages/c8/e8/c128e37589463668794d503afaeb003987373c5f94d667124ffd8078bbd9/lxml-6.0.2-cp314-cp314-macosx_10_13_x86_64.whl", hash = "sha256:4468e3b83e10e0317a89a33d28f7aeba1caa4d1a6fd457d115dd4ffe90c5931d", size = 4659403, upload-time = "2025-09-22T04:02:32.119Z" }, - { url = "https://files.pythonhosted.org/packages/00/ce/74903904339decdf7da7847bb5741fc98a5451b42fc419a86c0c13d26fe2/lxml-6.0.2-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:abd44571493973bad4598a3be7e1d807ed45aa2adaf7ab92ab7c62609569b17d", size = 4966974, upload-time = "2025-09-22T04:02:34.155Z" }, - { url = "https://files.pythonhosted.org/packages/1f/d3/131dec79ce61c5567fecf82515bd9bc36395df42501b50f7f7f3bd065df0/lxml-6.0.2-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:370cd78d5855cfbffd57c422851f7d3864e6ae72d0da615fca4dad8c45d375a5", size = 5102953, upload-time = "2025-09-22T04:02:36.054Z" }, - { url = "https://files.pythonhosted.org/packages/3a/ea/a43ba9bb750d4ffdd885f2cd333572f5bb900cd2408b67fdda07e85978a0/lxml-6.0.2-cp314-cp314-manylinux_2_26_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:901e3b4219fa04ef766885fb40fa516a71662a4c61b80c94d25336b4934b71c0", size = 5055054, upload-time = "2025-09-22T04:02:38.154Z" }, - { url = "https://files.pythonhosted.org/packages/60/23/6885b451636ae286c34628f70a7ed1fcc759f8d9ad382d132e1c8d3d9bfd/lxml-6.0.2-cp314-cp314-manylinux_2_26_i686.manylinux_2_28_i686.whl", hash = "sha256:a4bf42d2e4cf52c28cc1812d62426b9503cdb0c87a6de81442626aa7d69707ba", size = 5352421, upload-time = "2025-09-22T04:02:40.413Z" }, - { url = "https://files.pythonhosted.org/packages/48/5b/fc2ddfc94ddbe3eebb8e9af6e3fd65e2feba4967f6a4e9683875c394c2d8/lxml-6.0.2-cp314-cp314-manylinux_2_26_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:b2c7fdaa4d7c3d886a42534adec7cfac73860b89b4e5298752f60aa5984641a0", size = 5673684, upload-time = "2025-09-22T04:02:42.288Z" }, - { url = "https://files.pythonhosted.org/packages/29/9c/47293c58cc91769130fbf85531280e8cc7868f7fbb6d92f4670071b9cb3e/lxml-6.0.2-cp314-cp314-manylinux_2_26_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:98a5e1660dc7de2200b00d53fa00bcd3c35a3608c305d45a7bbcaf29fa16e83d", size = 5252463, upload-time = "2025-09-22T04:02:44.165Z" }, - { url = "https://files.pythonhosted.org/packages/9b/da/ba6eceb830c762b48e711ded880d7e3e89fc6c7323e587c36540b6b23c6b/lxml-6.0.2-cp314-cp314-manylinux_2_31_armv7l.whl", hash = "sha256:dc051506c30b609238d79eda75ee9cab3e520570ec8219844a72a46020901e37", size = 4698437, upload-time = "2025-09-22T04:02:46.524Z" }, - { url = "https://files.pythonhosted.org/packages/a5/24/7be3f82cb7990b89118d944b619e53c656c97dc89c28cfb143fdb7cd6f4d/lxml-6.0.2-cp314-cp314-manylinux_2_38_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:8799481bbdd212470d17513a54d568f44416db01250f49449647b5ab5b5dccb9", size = 5269890, upload-time = "2025-09-22T04:02:48.812Z" }, - { url = "https://files.pythonhosted.org/packages/1b/bd/dcfb9ea1e16c665efd7538fc5d5c34071276ce9220e234217682e7d2c4a5/lxml-6.0.2-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:9261bb77c2dab42f3ecd9103951aeca2c40277701eb7e912c545c1b16e0e4917", size = 5097185, upload-time = "2025-09-22T04:02:50.746Z" }, - { url = "https://files.pythonhosted.org/packages/21/04/a60b0ff9314736316f28316b694bccbbabe100f8483ad83852d77fc7468e/lxml-6.0.2-cp314-cp314-musllinux_1_2_armv7l.whl", hash = "sha256:65ac4a01aba353cfa6d5725b95d7aed6356ddc0a3cd734de00124d285b04b64f", size = 4745895, upload-time = "2025-09-22T04:02:52.968Z" }, - { url = "https://files.pythonhosted.org/packages/d6/bd/7d54bd1846e5a310d9c715921c5faa71cf5c0853372adf78aee70c8d7aa2/lxml-6.0.2-cp314-cp314-musllinux_1_2_ppc64le.whl", hash = "sha256:b22a07cbb82fea98f8a2fd814f3d1811ff9ed76d0fc6abc84eb21527596e7cc8", size = 5695246, upload-time = "2025-09-22T04:02:54.798Z" }, - { url = "https://files.pythonhosted.org/packages/fd/32/5643d6ab947bc371da21323acb2a6e603cedbe71cb4c99c8254289ab6f4e/lxml-6.0.2-cp314-cp314-musllinux_1_2_riscv64.whl", hash = "sha256:d759cdd7f3e055d6bc8d9bec3ad905227b2e4c785dc16c372eb5b5e83123f48a", size = 5260797, upload-time = "2025-09-22T04:02:57.058Z" }, - { url = "https://files.pythonhosted.org/packages/33/da/34c1ec4cff1eea7d0b4cd44af8411806ed943141804ac9c5d565302afb78/lxml-6.0.2-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:945da35a48d193d27c188037a05fec5492937f66fb1958c24fc761fb9d40d43c", size = 5277404, upload-time = "2025-09-22T04:02:58.966Z" }, - { url = "https://files.pythonhosted.org/packages/82/57/4eca3e31e54dc89e2c3507e1cd411074a17565fa5ffc437c4ae0a00d439e/lxml-6.0.2-cp314-cp314-win32.whl", hash = "sha256:be3aaa60da67e6153eb15715cc2e19091af5dc75faef8b8a585aea372507384b", size = 3670072, upload-time = "2025-09-22T04:03:38.05Z" }, - { url = "https://files.pythonhosted.org/packages/e3/e0/c96cf13eccd20c9421ba910304dae0f619724dcf1702864fd59dd386404d/lxml-6.0.2-cp314-cp314-win_amd64.whl", hash = "sha256:fa25afbadead523f7001caf0c2382afd272c315a033a7b06336da2637d92d6ed", size = 4080617, upload-time = "2025-09-22T04:03:39.835Z" }, - { url = "https://files.pythonhosted.org/packages/d5/5d/b3f03e22b3d38d6f188ef044900a9b29b2fe0aebb94625ce9fe244011d34/lxml-6.0.2-cp314-cp314-win_arm64.whl", hash = "sha256:063eccf89df5b24e361b123e257e437f9e9878f425ee9aae3144c77faf6da6d8", size = 3754930, upload-time = "2025-09-22T04:03:41.565Z" }, - { url = "https://files.pythonhosted.org/packages/5e/5c/42c2c4c03554580708fc738d13414801f340c04c3eff90d8d2d227145275/lxml-6.0.2-cp314-cp314t-macosx_10_13_universal2.whl", hash = "sha256:6162a86d86893d63084faaf4ff937b3daea233e3682fb4474db07395794fa80d", size = 8910380, upload-time = "2025-09-22T04:03:01.645Z" }, - { url = "https://files.pythonhosted.org/packages/bf/4f/12df843e3e10d18d468a7557058f8d3733e8b6e12401f30b1ef29360740f/lxml-6.0.2-cp314-cp314t-macosx_10_13_x86_64.whl", hash = "sha256:414aaa94e974e23a3e92e7ca5b97d10c0cf37b6481f50911032c69eeb3991bba", size = 4775632, upload-time = "2025-09-22T04:03:03.814Z" }, - { url = "https://files.pythonhosted.org/packages/e4/0c/9dc31e6c2d0d418483cbcb469d1f5a582a1cd00a1f4081953d44051f3c50/lxml-6.0.2-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:48461bd21625458dd01e14e2c38dd0aea69addc3c4f960c30d9f59d7f93be601", size = 4975171, upload-time = "2025-09-22T04:03:05.651Z" }, - { url = "https://files.pythonhosted.org/packages/e7/2b/9b870c6ca24c841bdd887504808f0417aa9d8d564114689266f19ddf29c8/lxml-6.0.2-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:25fcc59afc57d527cfc78a58f40ab4c9b8fd096a9a3f964d2781ffb6eb33f4ed", size = 5110109, upload-time = "2025-09-22T04:03:07.452Z" }, - { url = "https://files.pythonhosted.org/packages/bf/0c/4f5f2a4dd319a178912751564471355d9019e220c20d7db3fb8307ed8582/lxml-6.0.2-cp314-cp314t-manylinux_2_26_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:5179c60288204e6ddde3f774a93350177e08876eaf3ab78aa3a3649d43eb7d37", size = 5041061, upload-time = "2025-09-22T04:03:09.297Z" }, - { url = "https://files.pythonhosted.org/packages/12/64/554eed290365267671fe001a20d72d14f468ae4e6acef1e179b039436967/lxml-6.0.2-cp314-cp314t-manylinux_2_26_i686.manylinux_2_28_i686.whl", hash = "sha256:967aab75434de148ec80597b75062d8123cadf2943fb4281f385141e18b21338", size = 5306233, upload-time = "2025-09-22T04:03:11.651Z" }, - { url = "https://files.pythonhosted.org/packages/7a/31/1d748aa275e71802ad9722df32a7a35034246b42c0ecdd8235412c3396ef/lxml-6.0.2-cp314-cp314t-manylinux_2_26_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:d100fcc8930d697c6561156c6810ab4a508fb264c8b6779e6e61e2ed5e7558f9", size = 5604739, upload-time = "2025-09-22T04:03:13.592Z" }, - { url = "https://files.pythonhosted.org/packages/8f/41/2c11916bcac09ed561adccacceaedd2bf0e0b25b297ea92aab99fd03d0fa/lxml-6.0.2-cp314-cp314t-manylinux_2_26_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:2ca59e7e13e5981175b8b3e4ab84d7da57993eeff53c07764dcebda0d0e64ecd", size = 5225119, upload-time = "2025-09-22T04:03:15.408Z" }, - { url = "https://files.pythonhosted.org/packages/99/05/4e5c2873d8f17aa018e6afde417c80cc5d0c33be4854cce3ef5670c49367/lxml-6.0.2-cp314-cp314t-manylinux_2_31_armv7l.whl", hash = "sha256:957448ac63a42e2e49531b9d6c0fa449a1970dbc32467aaad46f11545be9af1d", size = 4633665, upload-time = "2025-09-22T04:03:17.262Z" }, - { url = "https://files.pythonhosted.org/packages/0f/c9/dcc2da1bebd6275cdc723b515f93edf548b82f36a5458cca3578bc899332/lxml-6.0.2-cp314-cp314t-manylinux_2_38_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:b7fc49c37f1786284b12af63152fe1d0990722497e2d5817acfe7a877522f9a9", size = 5234997, upload-time = "2025-09-22T04:03:19.14Z" }, - { url = "https://files.pythonhosted.org/packages/9c/e2/5172e4e7468afca64a37b81dba152fc5d90e30f9c83c7c3213d6a02a5ce4/lxml-6.0.2-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:e19e0643cc936a22e837f79d01a550678da8377d7d801a14487c10c34ee49c7e", size = 5090957, upload-time = "2025-09-22T04:03:21.436Z" }, - { url = "https://files.pythonhosted.org/packages/a5/b3/15461fd3e5cd4ddcb7938b87fc20b14ab113b92312fc97afe65cd7c85de1/lxml-6.0.2-cp314-cp314t-musllinux_1_2_armv7l.whl", hash = "sha256:1db01e5cf14345628e0cbe71067204db658e2fb8e51e7f33631f5f4735fefd8d", size = 4764372, upload-time = "2025-09-22T04:03:23.27Z" }, - { url = "https://files.pythonhosted.org/packages/05/33/f310b987c8bf9e61c4dd8e8035c416bd3230098f5e3cfa69fc4232de7059/lxml-6.0.2-cp314-cp314t-musllinux_1_2_ppc64le.whl", hash = "sha256:875c6b5ab39ad5291588aed6925fac99d0097af0dd62f33c7b43736043d4a2ec", size = 5634653, upload-time = "2025-09-22T04:03:25.767Z" }, - { url = "https://files.pythonhosted.org/packages/70/ff/51c80e75e0bc9382158133bdcf4e339b5886c6ee2418b5199b3f1a61ed6d/lxml-6.0.2-cp314-cp314t-musllinux_1_2_riscv64.whl", hash = "sha256:cdcbed9ad19da81c480dfd6dd161886db6096083c9938ead313d94b30aadf272", size = 5233795, upload-time = "2025-09-22T04:03:27.62Z" }, - { url = "https://files.pythonhosted.org/packages/56/4d/4856e897df0d588789dd844dbed9d91782c4ef0b327f96ce53c807e13128/lxml-6.0.2-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:80dadc234ebc532e09be1975ff538d154a7fa61ea5031c03d25178855544728f", size = 5257023, upload-time = "2025-09-22T04:03:30.056Z" }, - { url = "https://files.pythonhosted.org/packages/0f/85/86766dfebfa87bea0ab78e9ff7a4b4b45225df4b4d3b8cc3c03c5cd68464/lxml-6.0.2-cp314-cp314t-win32.whl", hash = "sha256:da08e7bb297b04e893d91087df19638dc7a6bb858a954b0cc2b9f5053c922312", size = 3911420, upload-time = "2025-09-22T04:03:32.198Z" }, - { url = "https://files.pythonhosted.org/packages/fe/1a/b248b355834c8e32614650b8008c69ffeb0ceb149c793961dd8c0b991bb3/lxml-6.0.2-cp314-cp314t-win_amd64.whl", hash = "sha256:252a22982dca42f6155125ac76d3432e548a7625d56f5a273ee78a5057216eca", size = 4406837, upload-time = "2025-09-22T04:03:34.027Z" }, - { url = "https://files.pythonhosted.org/packages/92/aa/df863bcc39c5e0946263454aba394de8a9084dbaff8ad143846b0d844739/lxml-6.0.2-cp314-cp314t-win_arm64.whl", hash = "sha256:bb4c1847b303835d89d785a18801a883436cdfd5dc3d62947f9c49e24f0f5a2c", size = 3822205, upload-time = "2025-09-22T04:03:36.249Z" }, -] - [[package]] name = "markdown-it-py" version = "3.0.0" @@ -1775,27 +1695,6 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/54/23/08c002201a8e7e1f9afba93b97deceb813252d9cfd0d3351caed123dcf97/numpy-2.3.4-cp314-cp314t-win_arm64.whl", hash = "sha256:8b5a9a39c45d852b62693d9b3f3e0fe052541f804296ff401a72a1b60edafb29", size = 10547532, upload-time = "2025-10-15T16:17:53.48Z" }, ] -[[package]] -name = "obspy" -version = "1.4.2" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "decorator" }, - { name = "lxml" }, - { name = "matplotlib" }, - { name = "numpy" }, - { name = "requests" }, - { name = "scipy" }, - { name = "setuptools" }, - { name = "sqlalchemy" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/13/98/108c3349aa18e2a2efb15d8cf7ab5b568f2f1a96d2411ce758546958d4ad/obspy-1.4.2.tar.gz", hash = "sha256:dd93a17cda32be057937b551f096df07def6aa61ccf26558ce9cd1866a70397c", size = 17036293, upload-time = "2025-04-30T12:45:15.835Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/e8/d0/64372c148fb552ea4b54fd9f44afed030430097a6b33540dcef7a195cae6/obspy-1.4.2-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:c24018ccdebf8cbc170af2dd9a86679f4baf074a7d645bdf017d50e3198baa8f", size = 14143750, upload-time = "2025-04-30T12:44:55.076Z" }, - { url = "https://files.pythonhosted.org/packages/ba/53/c1546cf83b763566b86dd2556276a92ab1e9900f77e4825898f1b810ec81/obspy-1.4.2-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:87bdde2cce9a12a85b77bd874bfe0d88457e8367aa21c653b78ab6c2e9f68622", size = 14523015, upload-time = "2025-04-30T12:44:57.576Z" }, - { url = "https://files.pythonhosted.org/packages/14/5f/e04dc347ae865c0c8e92aa9af8122d015fd1b85d5dd2bf29e522b6b94296/obspy-1.4.2-cp312-cp312-win_amd64.whl", hash = "sha256:a6fdd8693e55fada63e9bf36e5cbdfe1ebd231f4723fe1398ed6a7a4ee5de2ad", size = 14113148, upload-time = "2025-04-30T12:45:00.101Z" }, -] - [[package]] name = "osekit" version = "0.4.2b1" @@ -1804,7 +1703,6 @@ dependencies = [ { name = "matplotlib" }, { name = "notebook" }, { name = "numpy" }, - { name = "obspy" }, { name = "pandas" }, { name = "pytest" }, { name = "pyyaml" }, @@ -1834,7 +1732,6 @@ requires-dist = [ { name = "matplotlib", specifier = ">=3.10.7" }, { name = "notebook", specifier = ">=7.4.4" }, { name = "numpy", specifier = ">=2.2.6" }, - { name = "obspy", specifier = ">=1.4.2" }, { name = "pandas", specifier = ">=2.2.3" }, { name = "pytest", specifier = ">=8.3.5" }, { name = "pyyaml", specifier = ">=6.0.2" }, From 82602ad23b6f672665fe80f884e995cf1a1b66d2 Mon Sep 17 00:00:00 2001 From: Gautzilla Date: Fri, 19 Dec 2025 13:56:30 +0100 Subject: [PATCH 11/13] add mseed tests --- tests/test_audio.py | 200 ------------------------------------------ tests/test_mseed.py | 207 ++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 207 insertions(+), 200 deletions(-) create mode 100644 tests/test_mseed.py diff --git a/tests/test_audio.py b/tests/test_audio.py index 4017e696..c13149e5 100644 --- a/tests/test_audio.py +++ b/tests/test_audio.py @@ -254,206 +254,6 @@ def init_patch(self: AudioFile, *args: list, **kwargs: dict) -> None: ) -""" -@pytest.mark.parametrize( - ("streams", "files_begin", "begin", "end", "expected_data"), - [ - pytest.param( - [ - obspy.Stream( - obspy.Trace( - data=np.array(range(10), dtype=np.int32), - header={"sampling_rate": 10}, - ), - ), - ], - [Timestamp("2002-04-02 03:27:00")], - None, - None, - np.array(range(10)), - id="one_file_one_trace_full", - ), - pytest.param( - [ - obspy.Stream( - obspy.Trace( - data=np.array(range(10), dtype=np.int32), - header={"sampling_rate": 10}, - ), - ), - obspy.Stream( - obspy.Trace( - data=np.array(range(10, 20), dtype=np.int32), - header={"sampling_rate": 10}, - ), - ), - ], - [Timestamp("2002-04-02 03:27:00"), Timestamp("2002-04-02 03:27:01")], - None, - None, - np.array(range(20)), - id="multiple_files_one_trace_full", - ), - pytest.param( - [ - obspy.Stream( - [ - obspy.Trace( - data=np.array(range(10), dtype=np.int32), - header={"sampling_rate": 10}, - ), - obspy.Trace( - data=np.array(range(10, 20), dtype=np.int32), - header={"sampling_rate": 10}, - ), - ], - ), - ], - [Timestamp("2002-04-02 03:27:00")], - None, - None, - np.array(range(20)), - id="one_file_two_traces_full", - ), - pytest.param( - [ - obspy.Stream( - [ - obspy.Trace( - data=np.array(range(10), dtype=np.int32), - header={"sampling_rate": 10}, - ), - obspy.Trace( - data=np.array(range(10, 20), dtype=np.int32), - header={"sampling_rate": 10}, - ), - ], - ), - obspy.Stream( - obspy.Trace( - data=np.array(range(20, 30), dtype=np.int32), - header={"sampling_rate": 10}, - ), - ), - ], - [Timestamp("2002-04-02 03:27:00"), Timestamp("2002-04-02 03:27:02")], - None, - None, - np.array(range(30)), - id="multiple_files_multiple_traces_full", - ), - pytest.param( - [ - obspy.Stream( - obspy.Trace( - data=np.array(range(10), dtype=np.int32), - header={"sampling_rate": 10}, - ), - ), - ], - [Timestamp("2002-04-02 03:27:00")], - Timestamp("2002-04-02 03:27:00.23"), - Timestamp("2002-04-02 03:27:00.48"), - np.array(range(2, 4)), - id="one_file_one_trace_part", - ), - pytest.param( - [ - obspy.Stream( - [ - obspy.Trace( - data=np.array(range(10), dtype=np.int32), - header={"sampling_rate": 10}, - ), - obspy.Trace( - data=np.array(range(10, 20), dtype=np.int32), - header={"sampling_rate": 10}, - ), - ], - ), - obspy.Stream( - obspy.Trace( - data=np.array(range(20, 30), dtype=np.int32), - header={"sampling_rate": 10}, - ), - ), - ], - [Timestamp("2002-04-02 03:27:00"), Timestamp("2002-04-02 03:27:02")], - Timestamp("2002-04-02 03:27:00.85"), - Timestamp("2002-04-02 03:27:02.64"), - np.array(range(8, 26)), - id="multiple_files_multiple_traces_part", - ), - ], -) -def test_mseed_file_read( - tmp_path: pytest.fixture, - streams: list[obspy.Stream], - files_begin: list[pd.Timestamp], - begin: pd.Timestamp | None, - end: pd.Timestamp | None, - expected_data: np.ndarray, -) -> None: - # WRITE MSEED FILES - for stream, file_begin in zip(streams, files_begin, strict=False): - stream.write( - tmp_path - / f"{file_begin.strftime(TIMESTAMP_FORMATS_EXPORTED_FILES[1])}.mseed", - ) - - audio_files = sorted( - ( - AudioFile(path, strptime_format=TIMESTAMP_FORMATS_EXPORTED_FILES[1]) - for path in tmp_path.glob("*.mseed") - ), - key=lambda af: af.begin, - ) - - assert all( - audio_file.begin == file_begin - for audio_file, file_begin in zip(audio_files, files_begin, strict=True) - ) - assert all( - audio_file.sample_rate == stream.traces[0].meta.sampling_rate - for audio_file, stream in zip(audio_files, streams, strict=True) - ) - - audio_data = AudioData.from_files(audio_files, begin=begin, end=end) - - assert np.array_equal(audio_data.get_value(), expected_data) -""" - -""" -def test_inconsistent_mseed_sample_rate_error(tmp_path: pytest.fixture) -> None: - filename = ( - tmp_path - / f"{Timestamp('2002-04-02 03:27:00').strftime(TIMESTAMP_FORMATS_EXPORTED_FILES[1])}.mseed" - ) - - obspy.Stream( - [ - obspy.Trace( - data=np.array(range(10), dtype=np.int32), - header={"sampling_rate": 10}, - ), - obspy.Trace( - data=np.array(range(10, 20), dtype=np.int32), - header={"sampling_rate": 20}, - ), - ], - ).write(filename) - - with pytest.raises( - ValueError, - match="Audio file has inconsistent sampling rate.", - ) as e: - assert ( - AudioFile(filename, strptime_format=TIMESTAMP_FORMATS_EXPORTED_FILES[1]) - == e - ) -""" - - @pytest.mark.parametrize( ("audio_files", "start", "stop", "expected"), [ diff --git a/tests/test_mseed.py b/tests/test_mseed.py new file mode 100644 index 00000000..4e7d2952 --- /dev/null +++ b/tests/test_mseed.py @@ -0,0 +1,207 @@ +import numpy as np +import pandas as pd +import pytest +from pandas import Timestamp + +from osekit.config import TIMESTAMP_FORMATS_EXPORTED_FILES +from osekit.core_api.audio_data import AudioData +from osekit.core_api.audio_file import AudioFile + +obspy = pytest.importorskip("obspy") + + +@pytest.mark.parametrize( + ("streams", "files_begin", "begin", "end", "expected_data"), + [ + pytest.param( + [ + obspy.Stream( + obspy.Trace( + data=np.array(range(10), dtype=np.int32), + header={"sampling_rate": 10}, + ), + ), + ], + [Timestamp("2002-04-02 03:27:00")], + None, + None, + np.array(range(10)), + id="one_file_one_trace_full", + ), + pytest.param( + [ + obspy.Stream( + obspy.Trace( + data=np.array(range(10), dtype=np.int32), + header={"sampling_rate": 10}, + ), + ), + obspy.Stream( + obspy.Trace( + data=np.array(range(10, 20), dtype=np.int32), + header={"sampling_rate": 10}, + ), + ), + ], + [Timestamp("2002-04-02 03:27:00"), Timestamp("2002-04-02 03:27:01")], + None, + None, + np.array(range(20)), + id="multiple_files_one_trace_full", + ), + pytest.param( + [ + obspy.Stream( + [ + obspy.Trace( + data=np.array(range(10), dtype=np.int32), + header={"sampling_rate": 10}, + ), + obspy.Trace( + data=np.array(range(10, 20), dtype=np.int32), + header={"sampling_rate": 10}, + ), + ], + ), + ], + [Timestamp("2002-04-02 03:27:00")], + None, + None, + np.array(range(20)), + id="one_file_two_traces_full", + ), + pytest.param( + [ + obspy.Stream( + [ + obspy.Trace( + data=np.array(range(10), dtype=np.int32), + header={"sampling_rate": 10}, + ), + obspy.Trace( + data=np.array(range(10, 20), dtype=np.int32), + header={"sampling_rate": 10}, + ), + ], + ), + obspy.Stream( + obspy.Trace( + data=np.array(range(20, 30), dtype=np.int32), + header={"sampling_rate": 10}, + ), + ), + ], + [Timestamp("2002-04-02 03:27:00"), Timestamp("2002-04-02 03:27:02")], + None, + None, + np.array(range(30)), + id="multiple_files_multiple_traces_full", + ), + pytest.param( + [ + obspy.Stream( + obspy.Trace( + data=np.array(range(10), dtype=np.int32), + header={"sampling_rate": 10}, + ), + ), + ], + [Timestamp("2002-04-02 03:27:00")], + Timestamp("2002-04-02 03:27:00.23"), + Timestamp("2002-04-02 03:27:00.48"), + np.array(range(2, 4)), + id="one_file_one_trace_part", + ), + pytest.param( + [ + obspy.Stream( + [ + obspy.Trace( + data=np.array(range(10), dtype=np.int32), + header={"sampling_rate": 10}, + ), + obspy.Trace( + data=np.array(range(10, 20), dtype=np.int32), + header={"sampling_rate": 10}, + ), + ], + ), + obspy.Stream( + obspy.Trace( + data=np.array(range(20, 30), dtype=np.int32), + header={"sampling_rate": 10}, + ), + ), + ], + [Timestamp("2002-04-02 03:27:00"), Timestamp("2002-04-02 03:27:02")], + Timestamp("2002-04-02 03:27:00.85"), + Timestamp("2002-04-02 03:27:02.64"), + np.array(range(8, 26)), + id="multiple_files_multiple_traces_part", + ), + ], +) +def test_mseed_file_read( + tmp_path: pytest.fixture, + streams: list[obspy.Stream], + files_begin: list[pd.Timestamp], + begin: pd.Timestamp | None, + end: pd.Timestamp | None, + expected_data: np.ndarray, +) -> None: + # WRITE MSEED FILES + for stream, file_begin in zip(streams, files_begin, strict=False): + stream.write( + tmp_path + / f"{file_begin.strftime(TIMESTAMP_FORMATS_EXPORTED_FILES[1])}.mseed", + ) + + audio_files = sorted( + ( + AudioFile(path, strptime_format=TIMESTAMP_FORMATS_EXPORTED_FILES[1]) + for path in tmp_path.glob("*.mseed") + ), + key=lambda af: af.begin, + ) + + assert all( + audio_file.begin == file_begin + for audio_file, file_begin in zip(audio_files, files_begin, strict=True) + ) + assert all( + audio_file.sample_rate == stream.traces[0].meta.sampling_rate + for audio_file, stream in zip(audio_files, streams, strict=True) + ) + + audio_data = AudioData.from_files(audio_files, begin=begin, end=end) + + assert np.array_equal(audio_data.get_value(), expected_data) + + +def test_inconsistent_mseed_sample_rate_error(tmp_path: pytest.fixture) -> None: + filename = ( + tmp_path + / f"{Timestamp('2002-04-02 03:27:00').strftime(TIMESTAMP_FORMATS_EXPORTED_FILES[1])}.mseed" + ) + + obspy.Stream( + [ + obspy.Trace( + data=np.array(range(10), dtype=np.int32), + header={"sampling_rate": 10}, + ), + obspy.Trace( + data=np.array(range(10, 20), dtype=np.int32), + header={"sampling_rate": 20}, + ), + ], + ).write(filename) + + with pytest.raises( + ValueError, + match="Audio file has inconsistent sampling rate.", + ) as e: + assert ( + AudioFile(filename, strptime_format=TIMESTAMP_FORMATS_EXPORTED_FILES[1]) + == e + ) From e6f0da4df11e78e301bae55a10b2608458ca6530 Mon Sep 17 00:00:00 2001 From: Gautzilla Date: Fri, 19 Dec 2025 13:56:58 +0100 Subject: [PATCH 12/13] update lock --- uv.lock | 137 +++++++++++++++++++++++++++++++++++++++++++++++--------- 1 file changed, 116 insertions(+), 21 deletions(-) diff --git a/uv.lock b/uv.lock index b8673c19..a764a0f2 100644 --- a/uv.lock +++ b/uv.lock @@ -1280,6 +1280,86 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/a8/3e/1c6b43277de64fc3c0333b0e72ab7b52ddaaea205210d60d9b9f83c3d0c7/lark-1.3.0-py3-none-any.whl", hash = "sha256:80661f261fb2584a9828a097a2432efd575af27d20be0fd35d17f0fe37253831", size = 113002, upload-time = "2025-09-22T13:45:03.747Z" }, ] +[[package]] +name = "lxml" +version = "6.0.2" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/aa/88/262177de60548e5a2bfc46ad28232c9e9cbde697bd94132aeb80364675cb/lxml-6.0.2.tar.gz", hash = "sha256:cd79f3367bd74b317dda655dc8fcfa304d9eb6e4fb06b7168c5cf27f96e0cd62", size = 4073426, upload-time = "2025-09-22T04:04:59.287Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/f3/c8/8ff2bc6b920c84355146cd1ab7d181bc543b89241cfb1ebee824a7c81457/lxml-6.0.2-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:a59f5448ba2ceccd06995c95ea59a7674a10de0810f2ce90c9006f3cbc044456", size = 8661887, upload-time = "2025-09-22T04:01:17.265Z" }, + { url = "https://files.pythonhosted.org/packages/37/6f/9aae1008083bb501ef63284220ce81638332f9ccbfa53765b2b7502203cf/lxml-6.0.2-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:e8113639f3296706fbac34a30813929e29247718e88173ad849f57ca59754924", size = 4667818, upload-time = "2025-09-22T04:01:19.688Z" }, + { url = "https://files.pythonhosted.org/packages/f1/ca/31fb37f99f37f1536c133476674c10b577e409c0a624384147653e38baf2/lxml-6.0.2-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:a8bef9b9825fa8bc816a6e641bb67219489229ebc648be422af695f6e7a4fa7f", size = 4950807, upload-time = "2025-09-22T04:01:21.487Z" }, + { url = "https://files.pythonhosted.org/packages/da/87/f6cb9442e4bada8aab5ae7e1046264f62fdbeaa6e3f6211b93f4c0dd97f1/lxml-6.0.2-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:65ea18d710fd14e0186c2f973dc60bb52039a275f82d3c44a0e42b43440ea534", size = 5109179, upload-time = "2025-09-22T04:01:23.32Z" }, + { url = "https://files.pythonhosted.org/packages/c8/20/a7760713e65888db79bbae4f6146a6ae5c04e4a204a3c48896c408cd6ed2/lxml-6.0.2-cp312-cp312-manylinux_2_26_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:c371aa98126a0d4c739ca93ceffa0fd7a5d732e3ac66a46e74339acd4d334564", size = 5023044, upload-time = "2025-09-22T04:01:25.118Z" }, + { url = "https://files.pythonhosted.org/packages/a2/b0/7e64e0460fcb36471899f75831509098f3fd7cd02a3833ac517433cb4f8f/lxml-6.0.2-cp312-cp312-manylinux_2_26_i686.manylinux_2_28_i686.whl", hash = "sha256:700efd30c0fa1a3581d80a748157397559396090a51d306ea59a70020223d16f", size = 5359685, upload-time = "2025-09-22T04:01:27.398Z" }, + { url = "https://files.pythonhosted.org/packages/b9/e1/e5df362e9ca4e2f48ed6411bd4b3a0ae737cc842e96877f5bf9428055ab4/lxml-6.0.2-cp312-cp312-manylinux_2_26_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:c33e66d44fe60e72397b487ee92e01da0d09ba2d66df8eae42d77b6d06e5eba0", size = 5654127, upload-time = "2025-09-22T04:01:29.629Z" }, + { url = "https://files.pythonhosted.org/packages/c6/d1/232b3309a02d60f11e71857778bfcd4acbdb86c07db8260caf7d008b08f8/lxml-6.0.2-cp312-cp312-manylinux_2_26_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:90a345bbeaf9d0587a3aaffb7006aa39ccb6ff0e96a57286c0cb2fd1520ea192", size = 5253958, upload-time = "2025-09-22T04:01:31.535Z" }, + { url = "https://files.pythonhosted.org/packages/35/35/d955a070994725c4f7d80583a96cab9c107c57a125b20bb5f708fe941011/lxml-6.0.2-cp312-cp312-manylinux_2_31_armv7l.whl", hash = "sha256:064fdadaf7a21af3ed1dcaa106b854077fbeada827c18f72aec9346847cd65d0", size = 4711541, upload-time = "2025-09-22T04:01:33.801Z" }, + { url = "https://files.pythonhosted.org/packages/1e/be/667d17363b38a78c4bd63cfd4b4632029fd68d2c2dc81f25ce9eb5224dd5/lxml-6.0.2-cp312-cp312-manylinux_2_38_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:fbc74f42c3525ac4ffa4b89cbdd00057b6196bcefe8bce794abd42d33a018092", size = 5267426, upload-time = "2025-09-22T04:01:35.639Z" }, + { url = "https://files.pythonhosted.org/packages/ea/47/62c70aa4a1c26569bc958c9ca86af2bb4e1f614e8c04fb2989833874f7ae/lxml-6.0.2-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:6ddff43f702905a4e32bc24f3f2e2edfe0f8fde3277d481bffb709a4cced7a1f", size = 5064917, upload-time = "2025-09-22T04:01:37.448Z" }, + { url = "https://files.pythonhosted.org/packages/bd/55/6ceddaca353ebd0f1908ef712c597f8570cc9c58130dbb89903198e441fd/lxml-6.0.2-cp312-cp312-musllinux_1_2_armv7l.whl", hash = "sha256:6da5185951d72e6f5352166e3da7b0dc27aa70bd1090b0eb3f7f7212b53f1bb8", size = 4788795, upload-time = "2025-09-22T04:01:39.165Z" }, + { url = "https://files.pythonhosted.org/packages/cf/e8/fd63e15da5e3fd4c2146f8bbb3c14e94ab850589beab88e547b2dbce22e1/lxml-6.0.2-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:57a86e1ebb4020a38d295c04fc79603c7899e0df71588043eb218722dabc087f", size = 5676759, upload-time = "2025-09-22T04:01:41.506Z" }, + { url = "https://files.pythonhosted.org/packages/76/47/b3ec58dc5c374697f5ba37412cd2728f427d056315d124dd4b61da381877/lxml-6.0.2-cp312-cp312-musllinux_1_2_riscv64.whl", hash = "sha256:2047d8234fe735ab77802ce5f2297e410ff40f5238aec569ad7c8e163d7b19a6", size = 5255666, upload-time = "2025-09-22T04:01:43.363Z" }, + { url = "https://files.pythonhosted.org/packages/19/93/03ba725df4c3d72afd9596eef4a37a837ce8e4806010569bedfcd2cb68fd/lxml-6.0.2-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:6f91fd2b2ea15a6800c8e24418c0775a1694eefc011392da73bc6cef2623b322", size = 5277989, upload-time = "2025-09-22T04:01:45.215Z" }, + { url = "https://files.pythonhosted.org/packages/c6/80/c06de80bfce881d0ad738576f243911fccf992687ae09fd80b734712b39c/lxml-6.0.2-cp312-cp312-win32.whl", hash = "sha256:3ae2ce7d6fedfb3414a2b6c5e20b249c4c607f72cb8d2bb7cc9c6ec7c6f4e849", size = 3611456, upload-time = "2025-09-22T04:01:48.243Z" }, + { url = "https://files.pythonhosted.org/packages/f7/d7/0cdfb6c3e30893463fb3d1e52bc5f5f99684a03c29a0b6b605cfae879cd5/lxml-6.0.2-cp312-cp312-win_amd64.whl", hash = "sha256:72c87e5ee4e58a8354fb9c7c84cbf95a1c8236c127a5d1b7683f04bed8361e1f", size = 4011793, upload-time = "2025-09-22T04:01:50.042Z" }, + { url = "https://files.pythonhosted.org/packages/ea/7b/93c73c67db235931527301ed3785f849c78991e2e34f3fd9a6663ffda4c5/lxml-6.0.2-cp312-cp312-win_arm64.whl", hash = "sha256:61cb10eeb95570153e0c0e554f58df92ecf5109f75eacad4a95baa709e26c3d6", size = 3672836, upload-time = "2025-09-22T04:01:52.145Z" }, + { url = "https://files.pythonhosted.org/packages/53/fd/4e8f0540608977aea078bf6d79f128e0e2c2bba8af1acf775c30baa70460/lxml-6.0.2-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:9b33d21594afab46f37ae58dfadd06636f154923c4e8a4d754b0127554eb2e77", size = 8648494, upload-time = "2025-09-22T04:01:54.242Z" }, + { url = "https://files.pythonhosted.org/packages/5d/f4/2a94a3d3dfd6c6b433501b8d470a1960a20ecce93245cf2db1706adf6c19/lxml-6.0.2-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:6c8963287d7a4c5c9a432ff487c52e9c5618667179c18a204bdedb27310f022f", size = 4661146, upload-time = "2025-09-22T04:01:56.282Z" }, + { url = "https://files.pythonhosted.org/packages/25/2e/4efa677fa6b322013035d38016f6ae859d06cac67437ca7dc708a6af7028/lxml-6.0.2-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:1941354d92699fb5ffe6ed7b32f9649e43c2feb4b97205f75866f7d21aa91452", size = 4946932, upload-time = "2025-09-22T04:01:58.989Z" }, + { url = "https://files.pythonhosted.org/packages/ce/0f/526e78a6d38d109fdbaa5049c62e1d32fdd70c75fb61c4eadf3045d3d124/lxml-6.0.2-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:bb2f6ca0ae2d983ded09357b84af659c954722bbf04dea98030064996d156048", size = 5100060, upload-time = "2025-09-22T04:02:00.812Z" }, + { url = "https://files.pythonhosted.org/packages/81/76/99de58d81fa702cc0ea7edae4f4640416c2062813a00ff24bd70ac1d9c9b/lxml-6.0.2-cp313-cp313-manylinux_2_26_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:eb2a12d704f180a902d7fa778c6d71f36ceb7b0d317f34cdc76a5d05aa1dd1df", size = 5019000, upload-time = "2025-09-22T04:02:02.671Z" }, + { url = "https://files.pythonhosted.org/packages/b5/35/9e57d25482bc9a9882cb0037fdb9cc18f4b79d85df94fa9d2a89562f1d25/lxml-6.0.2-cp313-cp313-manylinux_2_26_i686.manylinux_2_28_i686.whl", hash = "sha256:6ec0e3f745021bfed19c456647f0298d60a24c9ff86d9d051f52b509663feeb1", size = 5348496, upload-time = "2025-09-22T04:02:04.904Z" }, + { url = "https://files.pythonhosted.org/packages/a6/8e/cb99bd0b83ccc3e8f0f528e9aa1f7a9965dfec08c617070c5db8d63a87ce/lxml-6.0.2-cp313-cp313-manylinux_2_26_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:846ae9a12d54e368933b9759052d6206a9e8b250291109c48e350c1f1f49d916", size = 5643779, upload-time = "2025-09-22T04:02:06.689Z" }, + { url = "https://files.pythonhosted.org/packages/d0/34/9e591954939276bb679b73773836c6684c22e56d05980e31d52a9a8deb18/lxml-6.0.2-cp313-cp313-manylinux_2_26_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:ef9266d2aa545d7374938fb5c484531ef5a2ec7f2d573e62f8ce722c735685fd", size = 5244072, upload-time = "2025-09-22T04:02:08.587Z" }, + { url = "https://files.pythonhosted.org/packages/8d/27/b29ff065f9aaca443ee377aff699714fcbffb371b4fce5ac4ca759e436d5/lxml-6.0.2-cp313-cp313-manylinux_2_31_armv7l.whl", hash = "sha256:4077b7c79f31755df33b795dc12119cb557a0106bfdab0d2c2d97bd3cf3dffa6", size = 4718675, upload-time = "2025-09-22T04:02:10.783Z" }, + { url = "https://files.pythonhosted.org/packages/2b/9f/f756f9c2cd27caa1a6ef8c32ae47aadea697f5c2c6d07b0dae133c244fbe/lxml-6.0.2-cp313-cp313-manylinux_2_38_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:a7c5d5e5f1081955358533be077166ee97ed2571d6a66bdba6ec2f609a715d1a", size = 5255171, upload-time = "2025-09-22T04:02:12.631Z" }, + { url = "https://files.pythonhosted.org/packages/61/46/bb85ea42d2cb1bd8395484fd72f38e3389611aa496ac7772da9205bbda0e/lxml-6.0.2-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:8f8d0cbd0674ee89863a523e6994ac25fd5be9c8486acfc3e5ccea679bad2679", size = 5057175, upload-time = "2025-09-22T04:02:14.718Z" }, + { url = "https://files.pythonhosted.org/packages/95/0c/443fc476dcc8e41577f0af70458c50fe299a97bb6b7505bb1ae09aa7f9ac/lxml-6.0.2-cp313-cp313-musllinux_1_2_armv7l.whl", hash = "sha256:2cbcbf6d6e924c28f04a43f3b6f6e272312a090f269eff68a2982e13e5d57659", size = 4785688, upload-time = "2025-09-22T04:02:16.957Z" }, + { url = "https://files.pythonhosted.org/packages/48/78/6ef0b359d45bb9697bc5a626e1992fa5d27aa3f8004b137b2314793b50a0/lxml-6.0.2-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:dfb874cfa53340009af6bdd7e54ebc0d21012a60a4e65d927c2e477112e63484", size = 5660655, upload-time = "2025-09-22T04:02:18.815Z" }, + { url = "https://files.pythonhosted.org/packages/ff/ea/e1d33808f386bc1339d08c0dcada6e4712d4ed8e93fcad5f057070b7988a/lxml-6.0.2-cp313-cp313-musllinux_1_2_riscv64.whl", hash = "sha256:fb8dae0b6b8b7f9e96c26fdd8121522ce5de9bb5538010870bd538683d30e9a2", size = 5247695, upload-time = "2025-09-22T04:02:20.593Z" }, + { url = "https://files.pythonhosted.org/packages/4f/47/eba75dfd8183673725255247a603b4ad606f4ae657b60c6c145b381697da/lxml-6.0.2-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:358d9adae670b63e95bc59747c72f4dc97c9ec58881d4627fe0120da0f90d314", size = 5269841, upload-time = "2025-09-22T04:02:22.489Z" }, + { url = "https://files.pythonhosted.org/packages/76/04/5c5e2b8577bc936e219becb2e98cdb1aca14a4921a12995b9d0c523502ae/lxml-6.0.2-cp313-cp313-win32.whl", hash = "sha256:e8cd2415f372e7e5a789d743d133ae474290a90b9023197fd78f32e2dc6873e2", size = 3610700, upload-time = "2025-09-22T04:02:24.465Z" }, + { url = "https://files.pythonhosted.org/packages/fe/0a/4643ccc6bb8b143e9f9640aa54e38255f9d3b45feb2cbe7ae2ca47e8782e/lxml-6.0.2-cp313-cp313-win_amd64.whl", hash = "sha256:b30d46379644fbfc3ab81f8f82ae4de55179414651f110a1514f0b1f8f6cb2d7", size = 4010347, upload-time = "2025-09-22T04:02:26.286Z" }, + { url = "https://files.pythonhosted.org/packages/31/ef/dcf1d29c3f530577f61e5fe2f1bd72929acf779953668a8a47a479ae6f26/lxml-6.0.2-cp313-cp313-win_arm64.whl", hash = "sha256:13dcecc9946dca97b11b7c40d29fba63b55ab4170d3c0cf8c0c164343b9bfdcf", size = 3671248, upload-time = "2025-09-22T04:02:27.918Z" }, + { url = "https://files.pythonhosted.org/packages/03/15/d4a377b385ab693ce97b472fe0c77c2b16ec79590e688b3ccc71fba19884/lxml-6.0.2-cp314-cp314-macosx_10_13_universal2.whl", hash = "sha256:b0c732aa23de8f8aec23f4b580d1e52905ef468afb4abeafd3fec77042abb6fe", size = 8659801, upload-time = "2025-09-22T04:02:30.113Z" }, + { url = "https://files.pythonhosted.org/packages/c8/e8/c128e37589463668794d503afaeb003987373c5f94d667124ffd8078bbd9/lxml-6.0.2-cp314-cp314-macosx_10_13_x86_64.whl", hash = "sha256:4468e3b83e10e0317a89a33d28f7aeba1caa4d1a6fd457d115dd4ffe90c5931d", size = 4659403, upload-time = "2025-09-22T04:02:32.119Z" }, + { url = "https://files.pythonhosted.org/packages/00/ce/74903904339decdf7da7847bb5741fc98a5451b42fc419a86c0c13d26fe2/lxml-6.0.2-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:abd44571493973bad4598a3be7e1d807ed45aa2adaf7ab92ab7c62609569b17d", size = 4966974, upload-time = "2025-09-22T04:02:34.155Z" }, + { url = "https://files.pythonhosted.org/packages/1f/d3/131dec79ce61c5567fecf82515bd9bc36395df42501b50f7f7f3bd065df0/lxml-6.0.2-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:370cd78d5855cfbffd57c422851f7d3864e6ae72d0da615fca4dad8c45d375a5", size = 5102953, upload-time = "2025-09-22T04:02:36.054Z" }, + { url = "https://files.pythonhosted.org/packages/3a/ea/a43ba9bb750d4ffdd885f2cd333572f5bb900cd2408b67fdda07e85978a0/lxml-6.0.2-cp314-cp314-manylinux_2_26_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:901e3b4219fa04ef766885fb40fa516a71662a4c61b80c94d25336b4934b71c0", size = 5055054, upload-time = "2025-09-22T04:02:38.154Z" }, + { url = "https://files.pythonhosted.org/packages/60/23/6885b451636ae286c34628f70a7ed1fcc759f8d9ad382d132e1c8d3d9bfd/lxml-6.0.2-cp314-cp314-manylinux_2_26_i686.manylinux_2_28_i686.whl", hash = "sha256:a4bf42d2e4cf52c28cc1812d62426b9503cdb0c87a6de81442626aa7d69707ba", size = 5352421, upload-time = "2025-09-22T04:02:40.413Z" }, + { url = "https://files.pythonhosted.org/packages/48/5b/fc2ddfc94ddbe3eebb8e9af6e3fd65e2feba4967f6a4e9683875c394c2d8/lxml-6.0.2-cp314-cp314-manylinux_2_26_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:b2c7fdaa4d7c3d886a42534adec7cfac73860b89b4e5298752f60aa5984641a0", size = 5673684, upload-time = "2025-09-22T04:02:42.288Z" }, + { url = "https://files.pythonhosted.org/packages/29/9c/47293c58cc91769130fbf85531280e8cc7868f7fbb6d92f4670071b9cb3e/lxml-6.0.2-cp314-cp314-manylinux_2_26_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:98a5e1660dc7de2200b00d53fa00bcd3c35a3608c305d45a7bbcaf29fa16e83d", size = 5252463, upload-time = "2025-09-22T04:02:44.165Z" }, + { url = "https://files.pythonhosted.org/packages/9b/da/ba6eceb830c762b48e711ded880d7e3e89fc6c7323e587c36540b6b23c6b/lxml-6.0.2-cp314-cp314-manylinux_2_31_armv7l.whl", hash = "sha256:dc051506c30b609238d79eda75ee9cab3e520570ec8219844a72a46020901e37", size = 4698437, upload-time = "2025-09-22T04:02:46.524Z" }, + { url = "https://files.pythonhosted.org/packages/a5/24/7be3f82cb7990b89118d944b619e53c656c97dc89c28cfb143fdb7cd6f4d/lxml-6.0.2-cp314-cp314-manylinux_2_38_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:8799481bbdd212470d17513a54d568f44416db01250f49449647b5ab5b5dccb9", size = 5269890, upload-time = "2025-09-22T04:02:48.812Z" }, + { url = "https://files.pythonhosted.org/packages/1b/bd/dcfb9ea1e16c665efd7538fc5d5c34071276ce9220e234217682e7d2c4a5/lxml-6.0.2-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:9261bb77c2dab42f3ecd9103951aeca2c40277701eb7e912c545c1b16e0e4917", size = 5097185, upload-time = "2025-09-22T04:02:50.746Z" }, + { url = "https://files.pythonhosted.org/packages/21/04/a60b0ff9314736316f28316b694bccbbabe100f8483ad83852d77fc7468e/lxml-6.0.2-cp314-cp314-musllinux_1_2_armv7l.whl", hash = "sha256:65ac4a01aba353cfa6d5725b95d7aed6356ddc0a3cd734de00124d285b04b64f", size = 4745895, upload-time = "2025-09-22T04:02:52.968Z" }, + { url = "https://files.pythonhosted.org/packages/d6/bd/7d54bd1846e5a310d9c715921c5faa71cf5c0853372adf78aee70c8d7aa2/lxml-6.0.2-cp314-cp314-musllinux_1_2_ppc64le.whl", hash = "sha256:b22a07cbb82fea98f8a2fd814f3d1811ff9ed76d0fc6abc84eb21527596e7cc8", size = 5695246, upload-time = "2025-09-22T04:02:54.798Z" }, + { url = "https://files.pythonhosted.org/packages/fd/32/5643d6ab947bc371da21323acb2a6e603cedbe71cb4c99c8254289ab6f4e/lxml-6.0.2-cp314-cp314-musllinux_1_2_riscv64.whl", hash = "sha256:d759cdd7f3e055d6bc8d9bec3ad905227b2e4c785dc16c372eb5b5e83123f48a", size = 5260797, upload-time = "2025-09-22T04:02:57.058Z" }, + { url = "https://files.pythonhosted.org/packages/33/da/34c1ec4cff1eea7d0b4cd44af8411806ed943141804ac9c5d565302afb78/lxml-6.0.2-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:945da35a48d193d27c188037a05fec5492937f66fb1958c24fc761fb9d40d43c", size = 5277404, upload-time = "2025-09-22T04:02:58.966Z" }, + { url = "https://files.pythonhosted.org/packages/82/57/4eca3e31e54dc89e2c3507e1cd411074a17565fa5ffc437c4ae0a00d439e/lxml-6.0.2-cp314-cp314-win32.whl", hash = "sha256:be3aaa60da67e6153eb15715cc2e19091af5dc75faef8b8a585aea372507384b", size = 3670072, upload-time = "2025-09-22T04:03:38.05Z" }, + { url = "https://files.pythonhosted.org/packages/e3/e0/c96cf13eccd20c9421ba910304dae0f619724dcf1702864fd59dd386404d/lxml-6.0.2-cp314-cp314-win_amd64.whl", hash = "sha256:fa25afbadead523f7001caf0c2382afd272c315a033a7b06336da2637d92d6ed", size = 4080617, upload-time = "2025-09-22T04:03:39.835Z" }, + { url = "https://files.pythonhosted.org/packages/d5/5d/b3f03e22b3d38d6f188ef044900a9b29b2fe0aebb94625ce9fe244011d34/lxml-6.0.2-cp314-cp314-win_arm64.whl", hash = "sha256:063eccf89df5b24e361b123e257e437f9e9878f425ee9aae3144c77faf6da6d8", size = 3754930, upload-time = "2025-09-22T04:03:41.565Z" }, + { url = "https://files.pythonhosted.org/packages/5e/5c/42c2c4c03554580708fc738d13414801f340c04c3eff90d8d2d227145275/lxml-6.0.2-cp314-cp314t-macosx_10_13_universal2.whl", hash = "sha256:6162a86d86893d63084faaf4ff937b3daea233e3682fb4474db07395794fa80d", size = 8910380, upload-time = "2025-09-22T04:03:01.645Z" }, + { url = "https://files.pythonhosted.org/packages/bf/4f/12df843e3e10d18d468a7557058f8d3733e8b6e12401f30b1ef29360740f/lxml-6.0.2-cp314-cp314t-macosx_10_13_x86_64.whl", hash = "sha256:414aaa94e974e23a3e92e7ca5b97d10c0cf37b6481f50911032c69eeb3991bba", size = 4775632, upload-time = "2025-09-22T04:03:03.814Z" }, + { url = "https://files.pythonhosted.org/packages/e4/0c/9dc31e6c2d0d418483cbcb469d1f5a582a1cd00a1f4081953d44051f3c50/lxml-6.0.2-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:48461bd21625458dd01e14e2c38dd0aea69addc3c4f960c30d9f59d7f93be601", size = 4975171, upload-time = "2025-09-22T04:03:05.651Z" }, + { url = "https://files.pythonhosted.org/packages/e7/2b/9b870c6ca24c841bdd887504808f0417aa9d8d564114689266f19ddf29c8/lxml-6.0.2-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:25fcc59afc57d527cfc78a58f40ab4c9b8fd096a9a3f964d2781ffb6eb33f4ed", size = 5110109, upload-time = "2025-09-22T04:03:07.452Z" }, + { url = "https://files.pythonhosted.org/packages/bf/0c/4f5f2a4dd319a178912751564471355d9019e220c20d7db3fb8307ed8582/lxml-6.0.2-cp314-cp314t-manylinux_2_26_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:5179c60288204e6ddde3f774a93350177e08876eaf3ab78aa3a3649d43eb7d37", size = 5041061, upload-time = "2025-09-22T04:03:09.297Z" }, + { url = "https://files.pythonhosted.org/packages/12/64/554eed290365267671fe001a20d72d14f468ae4e6acef1e179b039436967/lxml-6.0.2-cp314-cp314t-manylinux_2_26_i686.manylinux_2_28_i686.whl", hash = "sha256:967aab75434de148ec80597b75062d8123cadf2943fb4281f385141e18b21338", size = 5306233, upload-time = "2025-09-22T04:03:11.651Z" }, + { url = "https://files.pythonhosted.org/packages/7a/31/1d748aa275e71802ad9722df32a7a35034246b42c0ecdd8235412c3396ef/lxml-6.0.2-cp314-cp314t-manylinux_2_26_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:d100fcc8930d697c6561156c6810ab4a508fb264c8b6779e6e61e2ed5e7558f9", size = 5604739, upload-time = "2025-09-22T04:03:13.592Z" }, + { url = "https://files.pythonhosted.org/packages/8f/41/2c11916bcac09ed561adccacceaedd2bf0e0b25b297ea92aab99fd03d0fa/lxml-6.0.2-cp314-cp314t-manylinux_2_26_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:2ca59e7e13e5981175b8b3e4ab84d7da57993eeff53c07764dcebda0d0e64ecd", size = 5225119, upload-time = "2025-09-22T04:03:15.408Z" }, + { url = "https://files.pythonhosted.org/packages/99/05/4e5c2873d8f17aa018e6afde417c80cc5d0c33be4854cce3ef5670c49367/lxml-6.0.2-cp314-cp314t-manylinux_2_31_armv7l.whl", hash = "sha256:957448ac63a42e2e49531b9d6c0fa449a1970dbc32467aaad46f11545be9af1d", size = 4633665, upload-time = "2025-09-22T04:03:17.262Z" }, + { url = "https://files.pythonhosted.org/packages/0f/c9/dcc2da1bebd6275cdc723b515f93edf548b82f36a5458cca3578bc899332/lxml-6.0.2-cp314-cp314t-manylinux_2_38_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:b7fc49c37f1786284b12af63152fe1d0990722497e2d5817acfe7a877522f9a9", size = 5234997, upload-time = "2025-09-22T04:03:19.14Z" }, + { url = "https://files.pythonhosted.org/packages/9c/e2/5172e4e7468afca64a37b81dba152fc5d90e30f9c83c7c3213d6a02a5ce4/lxml-6.0.2-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:e19e0643cc936a22e837f79d01a550678da8377d7d801a14487c10c34ee49c7e", size = 5090957, upload-time = "2025-09-22T04:03:21.436Z" }, + { url = "https://files.pythonhosted.org/packages/a5/b3/15461fd3e5cd4ddcb7938b87fc20b14ab113b92312fc97afe65cd7c85de1/lxml-6.0.2-cp314-cp314t-musllinux_1_2_armv7l.whl", hash = "sha256:1db01e5cf14345628e0cbe71067204db658e2fb8e51e7f33631f5f4735fefd8d", size = 4764372, upload-time = "2025-09-22T04:03:23.27Z" }, + { url = "https://files.pythonhosted.org/packages/05/33/f310b987c8bf9e61c4dd8e8035c416bd3230098f5e3cfa69fc4232de7059/lxml-6.0.2-cp314-cp314t-musllinux_1_2_ppc64le.whl", hash = "sha256:875c6b5ab39ad5291588aed6925fac99d0097af0dd62f33c7b43736043d4a2ec", size = 5634653, upload-time = "2025-09-22T04:03:25.767Z" }, + { url = "https://files.pythonhosted.org/packages/70/ff/51c80e75e0bc9382158133bdcf4e339b5886c6ee2418b5199b3f1a61ed6d/lxml-6.0.2-cp314-cp314t-musllinux_1_2_riscv64.whl", hash = "sha256:cdcbed9ad19da81c480dfd6dd161886db6096083c9938ead313d94b30aadf272", size = 5233795, upload-time = "2025-09-22T04:03:27.62Z" }, + { url = "https://files.pythonhosted.org/packages/56/4d/4856e897df0d588789dd844dbed9d91782c4ef0b327f96ce53c807e13128/lxml-6.0.2-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:80dadc234ebc532e09be1975ff538d154a7fa61ea5031c03d25178855544728f", size = 5257023, upload-time = "2025-09-22T04:03:30.056Z" }, + { url = "https://files.pythonhosted.org/packages/0f/85/86766dfebfa87bea0ab78e9ff7a4b4b45225df4b4d3b8cc3c03c5cd68464/lxml-6.0.2-cp314-cp314t-win32.whl", hash = "sha256:da08e7bb297b04e893d91087df19638dc7a6bb858a954b0cc2b9f5053c922312", size = 3911420, upload-time = "2025-09-22T04:03:32.198Z" }, + { url = "https://files.pythonhosted.org/packages/fe/1a/b248b355834c8e32614650b8008c69ffeb0ceb149c793961dd8c0b991bb3/lxml-6.0.2-cp314-cp314t-win_amd64.whl", hash = "sha256:252a22982dca42f6155125ac76d3432e548a7625d56f5a273ee78a5057216eca", size = 4406837, upload-time = "2025-09-22T04:03:34.027Z" }, + { url = "https://files.pythonhosted.org/packages/92/aa/df863bcc39c5e0946263454aba394de8a9084dbaff8ad143846b0d844739/lxml-6.0.2-cp314-cp314t-win_arm64.whl", hash = "sha256:bb4c1847b303835d89d785a18801a883436cdfd5dc3d62947f9c49e24f0f5a2c", size = 3822205, upload-time = "2025-09-22T04:03:36.249Z" }, +] + [[package]] name = "markdown-it-py" version = "3.0.0" @@ -1695,6 +1775,27 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/54/23/08c002201a8e7e1f9afba93b97deceb813252d9cfd0d3351caed123dcf97/numpy-2.3.4-cp314-cp314t-win_arm64.whl", hash = "sha256:8b5a9a39c45d852b62693d9b3f3e0fe052541f804296ff401a72a1b60edafb29", size = 10547532, upload-time = "2025-10-15T16:17:53.48Z" }, ] +[[package]] +name = "obspy" +version = "1.4.2" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "decorator" }, + { name = "lxml" }, + { name = "matplotlib" }, + { name = "numpy" }, + { name = "requests" }, + { name = "scipy" }, + { name = "setuptools" }, + { name = "sqlalchemy" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/13/98/108c3349aa18e2a2efb15d8cf7ab5b568f2f1a96d2411ce758546958d4ad/obspy-1.4.2.tar.gz", hash = "sha256:dd93a17cda32be057937b551f096df07def6aa61ccf26558ce9cd1866a70397c", size = 17036293, upload-time = "2025-04-30T12:45:15.835Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/e8/d0/64372c148fb552ea4b54fd9f44afed030430097a6b33540dcef7a195cae6/obspy-1.4.2-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:c24018ccdebf8cbc170af2dd9a86679f4baf074a7d645bdf017d50e3198baa8f", size = 14143750, upload-time = "2025-04-30T12:44:55.076Z" }, + { url = "https://files.pythonhosted.org/packages/ba/53/c1546cf83b763566b86dd2556276a92ab1e9900f77e4825898f1b810ec81/obspy-1.4.2-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:87bdde2cce9a12a85b77bd874bfe0d88457e8367aa21c653b78ab6c2e9f68622", size = 14523015, upload-time = "2025-04-30T12:44:57.576Z" }, + { url = "https://files.pythonhosted.org/packages/14/5f/e04dc347ae865c0c8e92aa9af8122d015fd1b85d5dd2bf29e522b6b94296/obspy-1.4.2-cp312-cp312-win_amd64.whl", hash = "sha256:a6fdd8693e55fada63e9bf36e5cbdfe1ebd231f4723fe1398ed6a7a4ee5de2ad", size = 14113148, upload-time = "2025-04-30T12:45:00.101Z" }, +] + [[package]] name = "osekit" version = "0.4.2b1" @@ -1713,6 +1814,11 @@ dependencies = [ { name = "tqdm" }, ] +[package.optional-dependencies] +mseed = [ + { name = "obspy" }, +] + [package.dev-dependencies] dev = [ { name = "coverage" }, @@ -1732,6 +1838,7 @@ requires-dist = [ { name = "matplotlib", specifier = ">=3.10.7" }, { name = "notebook", specifier = ">=7.4.4" }, { name = "numpy", specifier = ">=2.2.6" }, + { name = "obspy", marker = "extra == 'mseed'" }, { name = "pandas", specifier = ">=2.2.3" }, { name = "pytest", specifier = ">=8.3.5" }, { name = "pyyaml", specifier = ">=6.0.2" }, @@ -1741,6 +1848,7 @@ requires-dist = [ { name = "tomlkit", specifier = ">=0.13.2" }, { name = "tqdm", specifier = ">=4.67.1" }, ] +provides-extras = ["mseed"] [package.metadata.requires-dev] dev = [ @@ -2706,31 +2814,18 @@ wheels = [ [[package]] name = "sqlalchemy" -version = "2.0.44" +version = "1.4.54" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "greenlet", marker = "platform_machine == 'AMD64' or platform_machine == 'WIN32' or platform_machine == 'aarch64' or platform_machine == 'amd64' or platform_machine == 'ppc64le' or platform_machine == 'win32' or platform_machine == 'x86_64'" }, - { name = "typing-extensions" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/f0/f2/840d7b9496825333f532d2e3976b8eadbf52034178aac53630d09fe6e1ef/sqlalchemy-2.0.44.tar.gz", hash = "sha256:0ae7454e1ab1d780aee69fd2aae7d6b8670a581d8847f2d1e0f7ddfbf47e5a22", size = 9819830, upload-time = "2025-10-10T14:39:12.935Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/62/c4/59c7c9b068e6813c898b771204aad36683c96318ed12d4233e1b18762164/sqlalchemy-2.0.44-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:72fea91746b5890f9e5e0997f16cbf3d53550580d76355ba2d998311b17b2250", size = 2139675, upload-time = "2025-10-10T16:03:31.064Z" }, - { url = "https://files.pythonhosted.org/packages/d6/ae/eeb0920537a6f9c5a3708e4a5fc55af25900216bdb4847ec29cfddf3bf3a/sqlalchemy-2.0.44-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:585c0c852a891450edbb1eaca8648408a3cc125f18cf433941fa6babcc359e29", size = 2127726, upload-time = "2025-10-10T16:03:35.934Z" }, - { url = "https://files.pythonhosted.org/packages/d8/d5/2ebbabe0379418eda8041c06b0b551f213576bfe4c2f09d77c06c07c8cc5/sqlalchemy-2.0.44-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:9b94843a102efa9ac68a7a30cd46df3ff1ed9c658100d30a725d10d9c60a2f44", size = 3327603, upload-time = "2025-10-10T15:35:28.322Z" }, - { url = "https://files.pythonhosted.org/packages/45/e5/5aa65852dadc24b7d8ae75b7efb8d19303ed6ac93482e60c44a585930ea5/sqlalchemy-2.0.44-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:119dc41e7a7defcefc57189cfa0e61b1bf9c228211aba432b53fb71ef367fda1", size = 3337842, upload-time = "2025-10-10T15:43:45.431Z" }, - { url = "https://files.pythonhosted.org/packages/41/92/648f1afd3f20b71e880ca797a960f638d39d243e233a7082c93093c22378/sqlalchemy-2.0.44-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:0765e318ee9179b3718c4fd7ba35c434f4dd20332fbc6857a5e8df17719c24d7", size = 3264558, upload-time = "2025-10-10T15:35:29.93Z" }, - { url = "https://files.pythonhosted.org/packages/40/cf/e27d7ee61a10f74b17740918e23cbc5bc62011b48282170dc4c66da8ec0f/sqlalchemy-2.0.44-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:2e7b5b079055e02d06a4308d0481658e4f06bc7ef211567edc8f7d5dce52018d", size = 3301570, upload-time = "2025-10-10T15:43:48.407Z" }, - { url = "https://files.pythonhosted.org/packages/3b/3d/3116a9a7b63e780fb402799b6da227435be878b6846b192f076d2f838654/sqlalchemy-2.0.44-cp312-cp312-win32.whl", hash = "sha256:846541e58b9a81cce7dee8329f352c318de25aa2f2bbe1e31587eb1f057448b4", size = 2103447, upload-time = "2025-10-10T15:03:21.678Z" }, - { url = "https://files.pythonhosted.org/packages/25/83/24690e9dfc241e6ab062df82cc0df7f4231c79ba98b273fa496fb3dd78ed/sqlalchemy-2.0.44-cp312-cp312-win_amd64.whl", hash = "sha256:7cbcb47fd66ab294703e1644f78971f6f2f1126424d2b300678f419aa73c7b6e", size = 2130912, upload-time = "2025-10-10T15:03:24.656Z" }, - { url = "https://files.pythonhosted.org/packages/45/d3/c67077a2249fdb455246e6853166360054c331db4613cda3e31ab1cadbef/sqlalchemy-2.0.44-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:ff486e183d151e51b1d694c7aa1695747599bb00b9f5f604092b54b74c64a8e1", size = 2135479, upload-time = "2025-10-10T16:03:37.671Z" }, - { url = "https://files.pythonhosted.org/packages/2b/91/eabd0688330d6fd114f5f12c4f89b0d02929f525e6bf7ff80aa17ca802af/sqlalchemy-2.0.44-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:0b1af8392eb27b372ddb783b317dea0f650241cea5bd29199b22235299ca2e45", size = 2123212, upload-time = "2025-10-10T16:03:41.755Z" }, - { url = "https://files.pythonhosted.org/packages/b0/bb/43e246cfe0e81c018076a16036d9b548c4cc649de241fa27d8d9ca6f85ab/sqlalchemy-2.0.44-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:2b61188657e3a2b9ac4e8f04d6cf8e51046e28175f79464c67f2fd35bceb0976", size = 3255353, upload-time = "2025-10-10T15:35:31.221Z" }, - { url = "https://files.pythonhosted.org/packages/b9/96/c6105ed9a880abe346b64d3b6ddef269ddfcab04f7f3d90a0bf3c5a88e82/sqlalchemy-2.0.44-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b87e7b91a5d5973dda5f00cd61ef72ad75a1db73a386b62877d4875a8840959c", size = 3260222, upload-time = "2025-10-10T15:43:50.124Z" }, - { url = "https://files.pythonhosted.org/packages/44/16/1857e35a47155b5ad927272fee81ae49d398959cb749edca6eaa399b582f/sqlalchemy-2.0.44-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:15f3326f7f0b2bfe406ee562e17f43f36e16167af99c4c0df61db668de20002d", size = 3189614, upload-time = "2025-10-10T15:35:32.578Z" }, - { url = "https://files.pythonhosted.org/packages/88/ee/4afb39a8ee4fc786e2d716c20ab87b5b1fb33d4ac4129a1aaa574ae8a585/sqlalchemy-2.0.44-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:1e77faf6ff919aa8cd63f1c4e561cac1d9a454a191bb864d5dd5e545935e5a40", size = 3226248, upload-time = "2025-10-10T15:43:51.862Z" }, - { url = "https://files.pythonhosted.org/packages/32/d5/0e66097fc64fa266f29a7963296b40a80d6a997b7ac13806183700676f86/sqlalchemy-2.0.44-cp313-cp313-win32.whl", hash = "sha256:ee51625c2d51f8baadf2829fae817ad0b66b140573939dd69284d2ba3553ae73", size = 2101275, upload-time = "2025-10-10T15:03:26.096Z" }, - { url = "https://files.pythonhosted.org/packages/03/51/665617fe4f8c6450f42a6d8d69243f9420f5677395572c2fe9d21b493b7b/sqlalchemy-2.0.44-cp313-cp313-win_amd64.whl", hash = "sha256:c1c80faaee1a6c3428cecf40d16a2365bcf56c424c92c2b6f0f9ad204b899e9e", size = 2127901, upload-time = "2025-10-10T15:03:27.548Z" }, - { url = "https://files.pythonhosted.org/packages/9c/5e/6a29fa884d9fb7ddadf6b69490a9d45fded3b38541713010dad16b77d015/sqlalchemy-2.0.44-py3-none-any.whl", hash = "sha256:19de7ca1246fbef9f9d1bff8f1ab25641569df226364a0e40457dc5457c54b05", size = 1928718, upload-time = "2025-10-10T15:29:45.32Z" }, +sdist = { url = "https://files.pythonhosted.org/packages/ce/af/20290b55d469e873cba9d41c0206ab5461ff49d759989b3fe65010f9d265/sqlalchemy-1.4.54.tar.gz", hash = "sha256:4470fbed088c35dc20b78a39aaf4ae54fe81790c783b3264872a0224f437c31a", size = 8470350, upload-time = "2024-09-05T15:54:10.398Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/a5/1b/aa9b99be95d1615f058b5827447c18505b7b3f1dfcbd6ce1b331c2107152/SQLAlchemy-1.4.54-cp312-cp312-macosx_10_9_universal2.whl", hash = "sha256:3f01c2629a7d6b30d8afe0326b8c649b74825a0e1ebdcb01e8ffd1c920deb07d", size = 1589983, upload-time = "2024-09-05T17:39:02.132Z" }, + { url = "https://files.pythonhosted.org/packages/59/47/cb0fc64e5344f0a3d02216796c342525ab283f8f052d1c31a1d487d08aa0/SQLAlchemy-1.4.54-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:9c24dd161c06992ed16c5e528a75878edbaeced5660c3db88c820f1f0d3fe1f4", size = 1630158, upload-time = "2024-09-05T17:50:13.255Z" }, + { url = "https://files.pythonhosted.org/packages/c0/8b/f45dd378f6c97e8ff9332ff3d03ecb0b8c491be5bb7a698783b5a2f358ec/SQLAlchemy-1.4.54-cp312-cp312-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b5e0d47d619c739bdc636bbe007da4519fc953393304a5943e0b5aec96c9877c", size = 1629232, upload-time = "2024-09-05T17:48:15.514Z" }, + { url = "https://files.pythonhosted.org/packages/0d/3c/884fe389f5bec86a310b81e79abaa1e26e5d78dc10a84d544a6822833e47/SQLAlchemy-1.4.54-cp312-cp312-win32.whl", hash = "sha256:12bc0141b245918b80d9d17eca94663dbd3f5266ac77a0be60750f36102bbb0f", size = 1592027, upload-time = "2024-09-05T17:54:02.253Z" }, + { url = "https://files.pythonhosted.org/packages/01/c3/c690d037be57efd3a69cde16a2ef1bd2a905dafe869434d33836de0983d0/SQLAlchemy-1.4.54-cp312-cp312-win_amd64.whl", hash = "sha256:f941aaf15f47f316123e1933f9ea91a6efda73a161a6ab6046d1cde37be62c88", size = 1593827, upload-time = "2024-09-05T17:52:07.454Z" }, ] [[package]] From 8190434b2e6ff82a0d06ae6ced1dc9dce40dc37a Mon Sep 17 00:00:00 2001 From: Gautzilla Date: Fri, 19 Dec 2025 14:10:12 +0100 Subject: [PATCH 13/13] fix error msg in tests --- src/osekit/audio_backend/mseed_backend.py | 2 +- tests/test_mseed.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/osekit/audio_backend/mseed_backend.py b/src/osekit/audio_backend/mseed_backend.py index f91f09f2..49cfd68b 100644 --- a/src/osekit/audio_backend/mseed_backend.py +++ b/src/osekit/audio_backend/mseed_backend.py @@ -35,7 +35,7 @@ def info(self, path: PathLike | str) -> tuple[int, int, int]: metadata = obspy.read(pathname_or_url=path, headonly=True) sample_rate = {trace.meta.sampling_rate for trace in metadata.traces} if len(sample_rate) != 1: - msg = "Inconsistent sampling rates in MSEED file" + msg = "Inconsistent sampling rates in MSEED file." raise ValueError(msg) frames = sum(trace.meta.npts for trace in metadata.traces) diff --git a/tests/test_mseed.py b/tests/test_mseed.py index 4e7d2952..c29c2bea 100644 --- a/tests/test_mseed.py +++ b/tests/test_mseed.py @@ -199,7 +199,7 @@ def test_inconsistent_mseed_sample_rate_error(tmp_path: pytest.fixture) -> None: with pytest.raises( ValueError, - match="Audio file has inconsistent sampling rate.", + match=r"Inconsistent sampling rates in MSEED file.", ) as e: assert ( AudioFile(filename, strptime_format=TIMESTAMP_FORMATS_EXPORTED_FILES[1])