From bf225be505abd77c88dc92199ff912b6fe21df46 Mon Sep 17 00:00:00 2001 From: Cail Daley Date: Thu, 16 Jul 2026 17:18:42 +0200 Subject: [PATCH 1/4] feat(mask): declare healsparse + hpgeom dependencies First step of the external-healsparse-mask path (#846): the reader rasterizes maskforce healsparse products onto image pixel grids in place of internal mask generation. Co-Authored-By: Claude Fable 5 Claude-Session: https://claude.ai/code/session_01CfRuCQa2UHo44yp2MZDsJX --- pyproject.toml | 2 + uv.lock | 1122 ++++++++++++++++++++++++------------------------ 2 files changed, 565 insertions(+), 559 deletions(-) diff --git a/pyproject.toml b/pyproject.toml index 8b259dee..5388adc8 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -24,6 +24,8 @@ dependencies = [ "cs_util>=0.2.1", "galsim>=2.8", "h5py", + "healsparse", + "hpgeom", "joblib>=1.4", "matplotlib>=3.10", "mccd>=1.2.4", diff --git a/uv.lock b/uv.lock index 03deab0a..3d024897 100644 --- a/uv.lock +++ b/uv.lock @@ -14,7 +14,7 @@ name = "accessible-pygments" version = "0.0.5" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "pygments" }, + { name = "pygments", marker = "sys_platform == 'linux'" }, ] sdist = { url = "https://files.pythonhosted.org/packages/bc/c1/bbac6a50d02774f91572938964c582fff4270eee73ab822a4aeea4d8b11b/accessible_pygments-0.0.5.tar.gz", hash = "sha256:40918d3e6a2b619ad424cb91e556bd3bd8865443d9f22f1dcdf79e33c8046872", size = 1377899, upload-time = "2024-05-10T11:23:10.216Z" } wheels = [ @@ -62,8 +62,8 @@ name = "anyio" version = "4.13.0" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "idna" }, - { name = "typing-extensions", marker = "python_full_version < '3.13'" }, + { name = "idna", marker = "sys_platform == 'linux'" }, + { name = "typing-extensions", marker = "python_full_version < '3.13' and sys_platform == 'linux'" }, ] sdist = { url = "https://files.pythonhosted.org/packages/19/14/2c5dd9f512b66549ae92767a9c7b330ae88e1932ca57876909410251fe13/anyio-4.13.0.tar.gz", hash = "sha256:334b70e641fd2221c1505b3890c69882fe4a2df910cba14d97019b90b24439dc", size = 231622, upload-time = "2026-03-24T12:59:09.671Z" } wheels = [ @@ -75,7 +75,7 @@ name = "argon2-cffi" version = "25.1.0" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "argon2-cffi-bindings" }, + { name = "argon2-cffi-bindings", marker = "sys_platform == 'linux'" }, ] sdist = { url = "https://files.pythonhosted.org/packages/0e/89/ce5af8a7d472a67cc819d5d998aa8c82c5d860608c4db9f46f1162d7dab9/argon2_cffi-25.1.0.tar.gz", hash = "sha256:694ae5cc8a42f4c4e2bf2ca0e64e51e23a040c6a517a85074683d3959e1346c1", size = 45706, upload-time = "2025-06-03T06:55:32.073Z" } wheels = [ @@ -87,7 +87,7 @@ name = "argon2-cffi-bindings" version = "25.1.0" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "cffi" }, + { name = "cffi", marker = "sys_platform == 'linux'" }, ] sdist = { url = "https://files.pythonhosted.org/packages/5c/2d/db8af0df73c1cf454f71b2bbe5e356b8c1f8041c979f505b3d3186e520a9/argon2_cffi_bindings-25.1.0.tar.gz", hash = "sha256:b957f3e6ea4d55d820e40ff76f450952807013d361a65d7f28acc0acbf29229d", size = 1783441, upload-time = "2025-07-30T10:02:05.147Z" } wheels = [ @@ -115,8 +115,8 @@ name = "arrow" version = "1.4.0" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "python-dateutil" }, - { name = "tzdata" }, + { name = "python-dateutil", marker = "sys_platform == 'linux'" }, + { name = "tzdata", marker = "sys_platform == 'linux'" }, ] sdist = { url = "https://files.pythonhosted.org/packages/b9/33/032cdc44182491aa708d06a68b62434140d8c50820a087fac7af37703357/arrow-1.4.0.tar.gz", hash = "sha256:ed0cc050e98001b8779e84d461b0098c4ac597e88704a655582b21d116e526d7", size = 152931, upload-time = "2025-10-18T17:46:46.761Z" } wheels = [ @@ -128,11 +128,11 @@ name = "astropy" version = "8.0.1" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "astropy-iers-data" }, - { name = "numpy" }, - { name = "packaging" }, - { name = "pyerfa" }, - { name = "pyyaml" }, + { name = "astropy-iers-data", marker = "sys_platform == 'linux'" }, + { name = "numpy", marker = "sys_platform == 'linux'" }, + { name = "packaging", marker = "sys_platform == 'linux'" }, + { name = "pyerfa", marker = "sys_platform == 'linux'" }, + { name = "pyyaml", marker = "sys_platform == 'linux'" }, ] sdist = { url = "https://files.pythonhosted.org/packages/0e/c4/21be4313ddfde5f60e0607fd307f367b9e0f0bf153a89b10cbd036dd8cfd/astropy-8.0.1.tar.gz", hash = "sha256:45ca31d5b91fa294cd590a4791a32db94de7f9c8a343155f4d5877baa82351da", size = 7152500, upload-time = "2026-07-05T07:24:48.482Z" } wheels = [ @@ -146,8 +146,8 @@ name = "astropy-healpix" version = "1.1.3" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "astropy" }, - { name = "numpy" }, + { name = "astropy", marker = "sys_platform == 'linux'" }, + { name = "numpy", marker = "sys_platform == 'linux'" }, ] sdist = { url = "https://files.pythonhosted.org/packages/ce/b1/7651302dd47b76d39c053c5a2f645b4a14a1ee1dfe1cc7491bcaa6b9fe20/astropy_healpix-1.1.3.tar.gz", hash = "sha256:f520d83abe8215d3e8e1a37b2bd91171ee36a6f55f110d5a2db863d75d81b3b7", size = 109331, upload-time = "2026-01-19T23:34:18.824Z" } wheels = [ @@ -173,13 +173,13 @@ name = "astroquery" version = "0.4.11" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "astropy" }, - { name = "beautifulsoup4" }, - { name = "html5lib" }, - { name = "keyring" }, - { name = "numpy" }, - { name = "pyvo" }, - { name = "requests" }, + { name = "astropy", marker = "sys_platform == 'linux'" }, + { name = "beautifulsoup4", marker = "sys_platform == 'linux'" }, + { name = "html5lib", marker = "sys_platform == 'linux'" }, + { name = "keyring", marker = "sys_platform == 'linux'" }, + { name = "numpy", marker = "sys_platform == 'linux'" }, + { name = "pyvo", marker = "sys_platform == 'linux'" }, + { name = "requests", marker = "sys_platform == 'linux'" }, ] sdist = { url = "https://files.pythonhosted.org/packages/32/48/273dbde090e071f9d264d084bc49193d126498d2906172b78febd9d62e28/astroquery-0.4.11.tar.gz", hash = "sha256:5537529bddc7fa07e773d5cd9baca593e3f5d93474edd1914f68e89506042b33", size = 12561055, upload-time = "2025-09-20T04:26:36.744Z" } wheels = [ @@ -227,8 +227,8 @@ name = "beautifulsoup4" version = "4.14.3" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "soupsieve" }, - { name = "typing-extensions" }, + { name = "soupsieve", marker = "sys_platform == 'linux'" }, + { name = "typing-extensions", marker = "sys_platform == 'linux'" }, ] sdist = { url = "https://files.pythonhosted.org/packages/c3/b0/1c6a16426d389813b48d95e26898aff79abbde42ad353958ad95cc8c9b21/beautifulsoup4-4.14.3.tar.gz", hash = "sha256:6292b1c5186d356bba669ef9f7f051757099565ad9ada5dd630bd9de5fa7fb86", size = 627737, upload-time = "2025-11-30T15:08:26.084Z" } wheels = [ @@ -240,7 +240,7 @@ name = "bleach" version = "6.4.0" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "webencodings" }, + { name = "webencodings", marker = "sys_platform == 'linux'" }, ] sdist = { url = "https://files.pythonhosted.org/packages/48/3c/e12ac860709702bd5ebeb9b56a4fe334f1001246ee1b8f2b7ee28912df7d/bleach-6.4.0.tar.gz", hash = "sha256:4202482733d85cedd04e59fcb2f89f4e4c7c385a78d3c3c23c30446843a37452", size = 204857, upload-time = "2026-06-05T13:01:13.734Z" } wheels = [ @@ -249,7 +249,7 @@ wheels = [ [package.optional-dependencies] css = [ - { name = "tinycss2" }, + { name = "tinycss2", marker = "sys_platform == 'linux'" }, ] [[package]] @@ -257,8 +257,8 @@ name = "build" version = "1.5.0" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "packaging" }, - { name = "pyproject-hooks" }, + { name = "packaging", marker = "sys_platform == 'linux'" }, + { name = "pyproject-hooks", marker = "sys_platform == 'linux'" }, ] sdist = { url = "https://files.pythonhosted.org/packages/78/e0/df5e171f685f82f37b12e1f208064e24244911079d7b767447d1af7e0d70/build-1.5.0.tar.gz", hash = "sha256:302c22c3ba2a0fd5f3911918651341ebb3896176cbdec15bd421f80b1afc7647", size = 89796, upload-time = "2026-04-30T03:18:25.17Z" } wheels = [ @@ -270,13 +270,13 @@ name = "cadcutils" version = "1.5.5" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "distro" }, - { name = "html2text" }, - { name = "lxml" }, - { name = "packaging" }, - { name = "pyopenssl" }, - { name = "requests" }, - { name = "setuptools" }, + { name = "distro", marker = "sys_platform == 'linux'" }, + { name = "html2text", marker = "sys_platform == 'linux'" }, + { name = "lxml", marker = "sys_platform == 'linux'" }, + { name = "packaging", marker = "sys_platform == 'linux'" }, + { name = "pyopenssl", marker = "sys_platform == 'linux'" }, + { name = "requests", marker = "sys_platform == 'linux'" }, + { name = "setuptools", marker = "sys_platform == 'linux'" }, ] sdist = { url = "https://files.pythonhosted.org/packages/f7/d6/1c3e4cb3f59cb2321d78f157723a22590a29854905487dcd994ea10cd63f/cadcutils-1.5.5.tar.gz", hash = "sha256:74600fdcdb4f2718576aa76b633a9e7b1989a8b37ca4cc9913cfd3ddd5415a75", size = 84921, upload-time = "2025-06-16T16:40:19.841Z" } wheels = [ @@ -288,10 +288,10 @@ name = "camb" version = "1.6.6" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "numpy" }, - { name = "packaging" }, - { name = "scipy" }, - { name = "sympy" }, + { name = "numpy", marker = "sys_platform == 'linux'" }, + { name = "packaging", marker = "sys_platform == 'linux'" }, + { name = "scipy", marker = "sys_platform == 'linux'" }, + { name = "sympy", marker = "sys_platform == 'linux'" }, ] sdist = { url = "https://files.pythonhosted.org/packages/6d/ad/f2e6446fbd94f7adc1474e1f4e40d2e7fa7e5e7143640cb8557d492f0a73/camb-1.6.6.tar.gz", hash = "sha256:9856202a5c05570256e52377b20431891c7b08b2e9c334e141fd08d2a085516f", size = 799344, upload-time = "2026-03-11T16:46:55.819Z" } wheels = [ @@ -304,18 +304,18 @@ name = "canfar" version = "1.3.5" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "cadcutils" }, - { name = "defusedxml" }, - { name = "httpx", extra = ["http2"] }, - { name = "humanize" }, - { name = "pydantic" }, - { name = "pydantic-settings" }, - { name = "pyyaml" }, - { name = "questionary" }, - { name = "rich" }, - { name = "segno" }, - { name = "toml" }, - { name = "typer" }, + { name = "cadcutils", marker = "sys_platform == 'linux'" }, + { name = "defusedxml", marker = "sys_platform == 'linux'" }, + { name = "httpx", extra = ["http2"], marker = "sys_platform == 'linux'" }, + { name = "humanize", marker = "sys_platform == 'linux'" }, + { name = "pydantic", marker = "sys_platform == 'linux'" }, + { name = "pydantic-settings", marker = "sys_platform == 'linux'" }, + { name = "pyyaml", marker = "sys_platform == 'linux'" }, + { name = "questionary", marker = "sys_platform == 'linux'" }, + { name = "rich", marker = "sys_platform == 'linux'" }, + { name = "segno", marker = "sys_platform == 'linux'" }, + { name = "toml", marker = "sys_platform == 'linux'" }, + { name = "typer", marker = "sys_platform == 'linux'" }, ] sdist = { url = "https://files.pythonhosted.org/packages/54/fc/4fa84863080e5db679c85a842794cae520d59a961a42969350d31569dcac/canfar-1.3.5.tar.gz", hash = "sha256:f4dd69e3426f5552f0cc4955642e8555d6c350bdf3598cd96251fb66241edaa4", size = 25689573, upload-time = "2026-04-28T15:36:01.33Z" } wheels = [ @@ -336,7 +336,7 @@ name = "cffi" version = "2.0.0" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "pycparser", marker = "implementation_name != 'PyPy'" }, + { name = "pycparser", marker = "implementation_name != 'PyPy' and sys_platform == 'linux'" }, ] sdist = { url = "https://files.pythonhosted.org/packages/eb/56/b1ba7935a17738ae8453301356628e8147c79dbb825bcbc73dc7401f9846/cffi-2.0.0.tar.gz", hash = "sha256:44d1b5909021139fe36001ae048dbdde8214afa20200eda0f64c068cac5d5529", size = 523588, upload-time = "2025-09-08T23:24:04.541Z" } wheels = [ @@ -466,7 +466,7 @@ name = "conda-inject" version = "1.3.2" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "pyyaml" }, + { name = "pyyaml", marker = "sys_platform == 'linux'" }, ] sdist = { url = "https://files.pythonhosted.org/packages/b1/a8/8dc86113c65c949cc72d651461d6e4c544b3302a85ed14a5298829e6a419/conda_inject-1.3.2.tar.gz", hash = "sha256:0b8cde8c47998c118d8ff285a04977a3abcf734caf579c520fca469df1cd0aac", size = 3635, upload-time = "2024-05-27T12:20:58.873Z" } wheels = [ @@ -493,7 +493,7 @@ name = "contourpy" version = "1.3.3" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "numpy" }, + { name = "numpy", marker = "sys_platform == 'linux'" }, ] sdist = { url = "https://files.pythonhosted.org/packages/58/01/1253e6698a07380cd31a736d248a3f2a50a7c88779a1813da27503cadc2a/contourpy-1.3.3.tar.gz", hash = "sha256:083e12155b210502d0bca491432bb04d56dc3432f95a979b429f2848c3dbe880", size = 13466174, upload-time = "2025-07-26T12:03:12.549Z" } wheels = [ @@ -593,7 +593,7 @@ name = "cryptography" version = "48.0.1" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "cffi", marker = "platform_python_implementation != 'PyPy'" }, + { name = "cffi", marker = "platform_python_implementation != 'PyPy' and sys_platform == 'linux'" }, ] sdist = { url = "https://files.pythonhosted.org/packages/12/45/870e7f4bef50e5f53b9f51d4428aee5290eedf58ba443f16b1ebb7ab8e66/cryptography-48.0.1.tar.gz", hash = "sha256:266f4ee051abb2f725b74ef8072b521ce1feacf685a3364fa6a6b45548db791a", size = 832989, upload-time = "2026-06-09T22:32:31.8Z" } wheels = [ @@ -637,18 +637,18 @@ name = "cs-util" version = "0.2.2" source = { git = "https://github.com/CosmoStat/cs_util?branch=develop#bedcdbf50ac57fc4d0b72a62b251373cd1807824" } dependencies = [ - { name = "astropy" }, - { name = "camb" }, - { name = "datetime" }, - { name = "healpy" }, - { name = "healsparse" }, - { name = "keyring" }, - { name = "matplotlib" }, - { name = "numpy" }, - { name = "pyccl" }, - { name = "scipy" }, - { name = "swig" }, - { name = "vos" }, + { name = "astropy", marker = "sys_platform == 'linux'" }, + { name = "camb", marker = "sys_platform == 'linux'" }, + { name = "datetime", marker = "sys_platform == 'linux'" }, + { name = "healpy", marker = "sys_platform == 'linux'" }, + { name = "healsparse", marker = "sys_platform == 'linux'" }, + { name = "keyring", marker = "sys_platform == 'linux'" }, + { name = "matplotlib", marker = "sys_platform == 'linux'" }, + { name = "numpy", marker = "sys_platform == 'linux'" }, + { name = "pyccl", marker = "sys_platform == 'linux'" }, + { name = "scipy", marker = "sys_platform == 'linux'" }, + { name = "swig", marker = "sys_platform == 'linux'" }, + { name = "vos", marker = "sys_platform == 'linux'" }, ] [[package]] @@ -665,13 +665,13 @@ name = "dask" version = "2026.3.0" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "click" }, - { name = "cloudpickle" }, - { name = "fsspec" }, - { name = "packaging" }, - { name = "partd" }, - { name = "pyyaml" }, - { name = "toolz" }, + { name = "click", marker = "sys_platform == 'linux'" }, + { name = "cloudpickle", marker = "sys_platform == 'linux'" }, + { name = "fsspec", marker = "sys_platform == 'linux'" }, + { name = "packaging", marker = "sys_platform == 'linux'" }, + { name = "partd", marker = "sys_platform == 'linux'" }, + { name = "pyyaml", marker = "sys_platform == 'linux'" }, + { name = "toolz", marker = "sys_platform == 'linux'" }, ] sdist = { url = "https://files.pythonhosted.org/packages/d7/2a/5d8cc1579590af86576dde890254440e478c7174b93a02095ecfc2e6ba38/dask-2026.3.0.tar.gz", hash = "sha256:f7d96c8274e8a900d217c1ff6ea8d1bbf0b4c2c21e74a409644498d925eb8f85", size = 11000710, upload-time = "2026-03-18T07:10:14.945Z" } wheels = [ @@ -680,12 +680,12 @@ wheels = [ [package.optional-dependencies] array = [ - { name = "numpy" }, + { name = "numpy", marker = "sys_platform == 'linux'" }, ] dataframe = [ - { name = "numpy" }, - { name = "pandas" }, - { name = "pyarrow" }, + { name = "numpy", marker = "sys_platform == 'linux'" }, + { name = "pandas", marker = "sys_platform == 'linux'" }, + { name = "pyarrow", marker = "sys_platform == 'linux'" }, ] [[package]] @@ -693,12 +693,12 @@ name = "dask-image" version = "2025.11.0" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "dask", extra = ["array", "dataframe"] }, - { name = "numpy" }, - { name = "pandas" }, - { name = "pims" }, - { name = "scipy" }, - { name = "tifffile" }, + { name = "dask", extra = ["array", "dataframe"], marker = "sys_platform == 'linux'" }, + { name = "numpy", marker = "sys_platform == 'linux'" }, + { name = "pandas", marker = "sys_platform == 'linux'" }, + { name = "pims", marker = "sys_platform == 'linux'" }, + { name = "scipy", marker = "sys_platform == 'linux'" }, + { name = "tifffile", marker = "sys_platform == 'linux'" }, ] sdist = { url = "https://files.pythonhosted.org/packages/5c/c4/7b83217443201469384a415687a8b89da8e55fc7a182e9507a69851a78b9/dask_image-2025.11.0.tar.gz", hash = "sha256:45cf1a9c3a8a1c143c75d43f1494e4fe0827564d3ec6efb93618fb04603ba0b3", size = 79561, upload-time = "2025-11-13T01:57:28.093Z" } wheels = [ @@ -710,8 +710,8 @@ name = "datetime" version = "6.0" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "pytz" }, - { name = "zope-interface" }, + { name = "pytz", marker = "sys_platform == 'linux'" }, + { name = "zope-interface", marker = "sys_platform == 'linux'" }, ] sdist = { url = "https://files.pythonhosted.org/packages/77/32/decbfd165e9985ba9d8c2d34a39afe5aeba2fc3fe390eb6e9ef1aab98fa8/datetime-6.0.tar.gz", hash = "sha256:c1514936d2f901e10c8e08d83bf04e6c9dbd7ca4f244da94fec980980a3bc4d5", size = 64167, upload-time = "2025-11-25T08:00:34.586Z" } wheels = [ @@ -771,7 +771,7 @@ name = "donfig" version = "0.8.1.post1" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "pyyaml" }, + { name = "pyyaml", marker = "sys_platform == 'linux'" }, ] sdist = { url = "https://files.pythonhosted.org/packages/25/71/80cc718ff6d7abfbabacb1f57aaa42e9c1552bfdd01e64ddd704e4a03638/donfig-0.8.1.post1.tar.gz", hash = "sha256:3bef3413a4c1c601b585e8d297256d0c1470ea012afa6e8461dc28bfb7c23f52", size = 19506, upload-time = "2024-05-23T14:14:31.513Z" } wheels = [ @@ -810,7 +810,7 @@ name = "fitsio" version = "1.3.0" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "numpy" }, + { name = "numpy", marker = "sys_platform == 'linux'" }, ] sdist = { url = "https://files.pythonhosted.org/packages/9e/f1/319003b56bcf6c83ef299461d601e13ad5910c1d62fa683d86fdb2fec2c6/fitsio-1.3.0.tar.gz", hash = "sha256:e2394fb0dca62f46feaaf61a48ad89fad6d2428a5a96a78ebfb4299a084b9260", size = 4995996, upload-time = "2025-11-12T15:24:25.021Z" } wheels = [ @@ -881,11 +881,11 @@ name = "galsim" version = "2.8.4" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "astropy" }, - { name = "lsstdesc-coord" }, - { name = "numpy" }, - { name = "pybind11" }, - { name = "setuptools" }, + { name = "astropy", marker = "sys_platform == 'linux'" }, + { name = "lsstdesc-coord", marker = "sys_platform == 'linux'" }, + { name = "numpy", marker = "sys_platform == 'linux'" }, + { name = "pybind11", marker = "sys_platform == 'linux'" }, + { name = "setuptools", marker = "sys_platform == 'linux'" }, ] sdist = { url = "https://files.pythonhosted.org/packages/72/59/c585e4de42d5b7f240a5bc4cd8ffd388b58cbde7515540f37d71da58623a/galsim-2.8.4.tar.gz", hash = "sha256:316299a0685e0bd6134ddf5642f39b439a2a35b7f116d6ebd979332fddbbad76", size = 8591085, upload-time = "2026-02-22T23:24:39.668Z" } wheels = [ @@ -904,7 +904,7 @@ name = "gitdb" version = "4.0.12" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "smmap" }, + { name = "smmap", marker = "sys_platform == 'linux'" }, ] sdist = { url = "https://files.pythonhosted.org/packages/72/94/63b0fc47eb32792c7ba1fe1b694daec9a63620db1e313033d18140c2320a/gitdb-4.0.12.tar.gz", hash = "sha256:5ef71f855d191a3326fcfbc0d5da835f26b13fbcba60c32c21091c349ffdb571", size = 394684, upload-time = "2025-01-02T07:20:46.413Z" } wheels = [ @@ -916,7 +916,7 @@ name = "gitpython" version = "3.1.50" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "gitdb" }, + { name = "gitdb", marker = "sys_platform == 'linux'" }, ] sdist = { url = "https://files.pythonhosted.org/packages/33/f6/354ae6491228b5eb40e10d89c4d13c651fe1cf7556e35ebdded50cff57ce/gitpython-3.1.50.tar.gz", hash = "sha256:80da2d12504d52e1f998772dc5baf6e553f8d2fcfe1fcc226c9d9a2ee3372dcc", size = 219798, upload-time = "2026-05-06T04:01:26.571Z" } wheels = [ @@ -979,8 +979,8 @@ name = "h2" version = "4.3.0" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "hpack" }, - { name = "hyperframe" }, + { name = "hpack", marker = "sys_platform == 'linux'" }, + { name = "hyperframe", marker = "sys_platform == 'linux'" }, ] sdist = { url = "https://files.pythonhosted.org/packages/1d/17/afa56379f94ad0fe8defd37d6eb3f89a25404ffc71d4d848893d270325fc/h2-4.3.0.tar.gz", hash = "sha256:6c59efe4323fa18b47a632221a1888bd7fde6249819beda254aeca909f221bf1", size = 2152026, upload-time = "2025-08-23T18:12:19.778Z" } wheels = [ @@ -992,7 +992,7 @@ name = "h5py" version = "3.16.0" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "numpy" }, + { name = "numpy", marker = "sys_platform == 'linux'" }, ] sdist = { url = "https://files.pythonhosted.org/packages/db/33/acd0ce6863b6c0d7735007df01815403f5589a21ff8c2e1ee2587a38f548/h5py-3.16.0.tar.gz", hash = "sha256:a0dbaad796840ccaa67a4c144a0d0c8080073c34c76d5a6941d6818678ef2738", size = 446526, upload-time = "2026-03-06T13:49:08.07Z" } wheels = [ @@ -1019,8 +1019,8 @@ name = "healpy" version = "1.19.0" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "astropy" }, - { name = "numpy" }, + { name = "astropy", marker = "sys_platform == 'linux'" }, + { name = "numpy", marker = "sys_platform == 'linux'" }, ] sdist = { url = "https://files.pythonhosted.org/packages/e3/4e/6f5328f375f88c8c38314f24f82b7e1486ec0358c557779500382db1503c/healpy-1.19.0.tar.gz", hash = "sha256:28e839cb885a23d36c77fc3423a3cb9271a07fda94085bd12fc329f941130ec5", size = 4075006, upload-time = "2025-12-02T08:27:19.766Z" } wheels = [ @@ -1043,9 +1043,9 @@ name = "healsparse" version = "1.12.2" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "astropy" }, - { name = "hpgeom" }, - { name = "numpy" }, + { name = "astropy", marker = "sys_platform == 'linux'" }, + { name = "hpgeom", marker = "sys_platform == 'linux'" }, + { name = "numpy", marker = "sys_platform == 'linux'" }, ] sdist = { url = "https://files.pythonhosted.org/packages/72/c1/ba1dcceb6fc7d10f2f92e0019e865fef7e11ea8bbd544b5691d94d03b41c/healsparse-1.12.2.tar.gz", hash = "sha256:364e2c9966698843139c53ad878dcc8d544658d13005545d11fbc0935bc6a4b6", size = 131452, upload-time = "2026-03-17T15:04:37.646Z" } wheels = [ @@ -1066,7 +1066,7 @@ name = "hpgeom" version = "1.5.4" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "numpy" }, + { name = "numpy", marker = "sys_platform == 'linux'" }, ] sdist = { url = "https://files.pythonhosted.org/packages/07/72/27640de7d85a566b8ecd27e7894f371a19669c56c268756e18111a137df8/hpgeom-1.5.4.tar.gz", hash = "sha256:85ac73e267c11f3f248920d3541a0e6ffab821cae54f0d44414d1939dfb91200", size = 153906, upload-time = "2026-02-24T19:03:01.954Z" } wheels = [ @@ -1092,8 +1092,8 @@ name = "html5lib" version = "1.1" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "six" }, - { name = "webencodings" }, + { name = "six", marker = "sys_platform == 'linux'" }, + { name = "webencodings", marker = "sys_platform == 'linux'" }, ] sdist = { url = "https://files.pythonhosted.org/packages/ac/b6/b55c3f49042f1df3dcd422b7f224f939892ee94f22abcf503a9b7339eaf2/html5lib-1.1.tar.gz", hash = "sha256:b2e5b40261e20f354d198eae92afc10d750afb487ed5e50f9c4eaf07c184146f", size = 272215, upload-time = "2020-06-22T23:32:38.834Z" } wheels = [ @@ -1105,8 +1105,8 @@ name = "httpcore" version = "1.0.9" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "certifi" }, - { name = "h11" }, + { name = "certifi", marker = "sys_platform == 'linux'" }, + { name = "h11", marker = "sys_platform == 'linux'" }, ] sdist = { url = "https://files.pythonhosted.org/packages/06/94/82699a10bca87a5556c9c59b5963f2d039dbd239f25bc2a63907a05a14cb/httpcore-1.0.9.tar.gz", hash = "sha256:6e34463af53fd2ab5d807f399a9b45ea31c3dfa2276f15a2c3f00afff6e176e8", size = 85484, upload-time = "2025-04-24T22:06:22.219Z" } wheels = [ @@ -1118,10 +1118,10 @@ name = "httpx" version = "0.28.1" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "anyio" }, - { name = "certifi" }, - { name = "httpcore" }, - { name = "idna" }, + { name = "anyio", marker = "sys_platform == 'linux'" }, + { name = "certifi", marker = "sys_platform == 'linux'" }, + { name = "httpcore", marker = "sys_platform == 'linux'" }, + { name = "idna", marker = "sys_platform == 'linux'" }, ] sdist = { url = "https://files.pythonhosted.org/packages/b1/df/48c586a5fe32a0f01324ee087459e112ebb7224f646c0b5023f5e79e9956/httpx-0.28.1.tar.gz", hash = "sha256:75e98c5f16b0f35b567856f597f06ff2270a374470a5c2392242528e3e3e42fc", size = 141406, upload-time = "2024-12-06T15:37:23.222Z" } wheels = [ @@ -1130,7 +1130,7 @@ wheels = [ [package.optional-dependencies] http2 = [ - { name = "h2" }, + { name = "h2", marker = "sys_platform == 'linux'" }, ] [[package]] @@ -1165,7 +1165,7 @@ name = "hypothesis" version = "6.156.6" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "sortedcontainers" }, + { name = "sortedcontainers", marker = "sys_platform == 'linux'" }, ] sdist = { url = "https://files.pythonhosted.org/packages/20/83/8dbe89bdb8c6f25a7a52e7898af6d82fe35dfef08e5c702f6e33231ce6c6/hypothesis-6.156.6.tar.gz", hash = "sha256:96de02faefa3ce079873541da96f42595583bb001e8e4219294ed7d4501cc4cc", size = 476304, upload-time = "2026-07-10T20:56:49.96Z" } wheels = [ @@ -1198,7 +1198,7 @@ name = "id" version = "1.6.1" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "urllib3" }, + { name = "urllib3", marker = "sys_platform == 'linux'" }, ] sdist = { url = "https://files.pythonhosted.org/packages/6d/04/c2156091427636080787aac190019dc64096e56a23b7364d3c1764ee3a06/id-1.6.1.tar.gz", hash = "sha256:d0732d624fb46fd4e7bc4e5152f00214450953b9e772c182c1c22964def1a069", size = 18088, upload-time = "2026-02-04T16:19:41.26Z" } wheels = [ @@ -1219,8 +1219,8 @@ name = "imageio" version = "2.37.3" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "numpy" }, - { name = "pillow" }, + { name = "numpy", marker = "sys_platform == 'linux'" }, + { name = "pillow", marker = "sys_platform == 'linux'" }, ] sdist = { url = "https://files.pythonhosted.org/packages/b1/84/93bcd1300216ea50811cee96873b84a1bebf8d0489ffaf7f2a3756bab866/imageio-2.37.3.tar.gz", hash = "sha256:bbb37efbfc4c400fcd534b367b91fcd66d5da639aaa138034431a1c5e0a41451", size = 389673, upload-time = "2026-03-09T11:31:12.573Z" } wheels = [ @@ -1257,7 +1257,7 @@ name = "importlib-metadata" version = "9.0.0" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "zipp" }, + { name = "zipp", marker = "sys_platform == 'linux'" }, ] sdist = { url = "https://files.pythonhosted.org/packages/a9/01/15bb152d77b21318514a96f43af312635eb2500c96b55398d020c93d86ea/importlib_metadata-9.0.0.tar.gz", hash = "sha256:a4f57ab599e6a2e3016d7595cfd72eb4661a5106e787a95bcc90c7105b831efc", size = 56405, upload-time = "2026-03-20T06:42:56.999Z" } wheels = [ @@ -1278,18 +1278,18 @@ name = "ipykernel" version = "7.2.0" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "comm" }, - { name = "debugpy" }, - { name = "ipython" }, - { name = "jupyter-client" }, - { name = "jupyter-core" }, - { name = "matplotlib-inline" }, - { name = "nest-asyncio" }, - { name = "packaging" }, - { name = "psutil" }, - { name = "pyzmq" }, - { name = "tornado" }, - { name = "traitlets" }, + { name = "comm", marker = "sys_platform == 'linux'" }, + { name = "debugpy", marker = "sys_platform == 'linux'" }, + { name = "ipython", marker = "sys_platform == 'linux'" }, + { name = "jupyter-client", marker = "sys_platform == 'linux'" }, + { name = "jupyter-core", marker = "sys_platform == 'linux'" }, + { name = "matplotlib-inline", marker = "sys_platform == 'linux'" }, + { name = "nest-asyncio", marker = "sys_platform == 'linux'" }, + { name = "packaging", marker = "sys_platform == 'linux'" }, + { name = "psutil", marker = "sys_platform == 'linux'" }, + { name = "pyzmq", marker = "sys_platform == 'linux'" }, + { name = "tornado", marker = "sys_platform == 'linux'" }, + { name = "traitlets", marker = "sys_platform == 'linux'" }, ] sdist = { url = "https://files.pythonhosted.org/packages/ca/8d/b68b728e2d06b9e0051019640a40a9eb7a88fcd82c2e1b5ce70bef5ff044/ipykernel-7.2.0.tar.gz", hash = "sha256:18ed160b6dee2cbb16e5f3575858bc19d8f1fe6046a9a680c708494ce31d909e", size = 176046, upload-time = "2026-02-06T16:43:27.403Z" } wheels = [ @@ -1301,16 +1301,16 @@ name = "ipython" version = "9.15.0" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "decorator" }, - { name = "ipython-pygments-lexers" }, - { name = "jedi" }, - { name = "matplotlib-inline" }, - { name = "pexpect" }, - { name = "prompt-toolkit" }, - { name = "psutil" }, - { name = "pygments" }, - { name = "stack-data" }, - { name = "traitlets" }, + { name = "decorator", marker = "sys_platform == 'linux'" }, + { name = "ipython-pygments-lexers", marker = "sys_platform == 'linux'" }, + { name = "jedi", marker = "sys_platform == 'linux'" }, + { name = "matplotlib-inline", marker = "sys_platform == 'linux'" }, + { name = "pexpect", marker = "sys_platform == 'linux'" }, + { name = "prompt-toolkit", marker = "sys_platform == 'linux'" }, + { name = "psutil", marker = "sys_platform == 'linux'" }, + { name = "pygments", marker = "sys_platform == 'linux'" }, + { name = "stack-data", marker = "sys_platform == 'linux'" }, + { name = "traitlets", marker = "sys_platform == 'linux'" }, ] sdist = { url = "https://files.pythonhosted.org/packages/53/59/165d3b4d75cc34add3122c4417ecb229085140ac573103c223cd01dde96f/ipython-9.15.0.tar.gz", hash = "sha256:da2819ce2aa83135257df830660b1176d986c3d2876db24df01974fa955b2756", size = 4442580, upload-time = "2026-06-26T11:03:35.913Z" } wheels = [ @@ -1322,7 +1322,7 @@ name = "ipython-pygments-lexers" version = "1.1.1" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "pygments" }, + { name = "pygments", marker = "sys_platform == 'linux'" }, ] sdist = { url = "https://files.pythonhosted.org/packages/ef/4c/5dd1d8af08107f88c7f741ead7a40854b8ac24ddf9ae850afbcf698aa552/ipython_pygments_lexers-1.1.1.tar.gz", hash = "sha256:09c0138009e56b6854f9535736f4171d855c8c08a563a0dcd8022f78355c7e81", size = 8393, upload-time = "2025-01-17T11:24:34.505Z" } wheels = [ @@ -1334,7 +1334,7 @@ name = "isoduration" version = "20.11.0" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "arrow" }, + { name = "arrow", marker = "sys_platform == 'linux'" }, ] sdist = { url = "https://files.pythonhosted.org/packages/7c/1a/3c8edc664e06e6bd06cce40c6b22da5f1429aa4224d0c590f3be21c91ead/isoduration-20.11.0.tar.gz", hash = "sha256:ac2f9015137935279eac671f94f89eb00584f940f5dc49462a0c4ee692ba1bd9", size = 11649, upload-time = "2020-11-01T11:00:00.312Z" } wheels = [ @@ -1346,7 +1346,7 @@ name = "jaraco-classes" version = "3.4.0" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "more-itertools" }, + { name = "more-itertools", marker = "sys_platform == 'linux'" }, ] sdist = { url = "https://files.pythonhosted.org/packages/06/c0/ed4a27bc5571b99e3cff68f8a9fa5b56ff7df1c2251cc715a652ddd26402/jaraco.classes-3.4.0.tar.gz", hash = "sha256:47a024b51d0239c0dd8c8540c6c7f484be3b8fcf0b2d85c13825780d3b3f3acd", size = 11780, upload-time = "2024-03-31T07:27:36.643Z" } wheels = [ @@ -1367,7 +1367,7 @@ name = "jaraco-functools" version = "4.4.0" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "more-itertools" }, + { name = "more-itertools", marker = "sys_platform == 'linux'" }, ] sdist = { url = "https://files.pythonhosted.org/packages/0f/27/056e0638a86749374d6f57d0b0db39f29509cce9313cf91bdc0ac4d91084/jaraco_functools-4.4.0.tar.gz", hash = "sha256:da21933b0417b89515562656547a77b4931f98176eb173644c0d35032a33d6bb", size = 19943, upload-time = "2025-12-21T09:29:43.6Z" } wheels = [ @@ -1379,7 +1379,7 @@ name = "jedi" version = "0.19.2" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "parso" }, + { name = "parso", marker = "sys_platform == 'linux'" }, ] sdist = { url = "https://files.pythonhosted.org/packages/72/3a/79a912fbd4d8dd6fbb02bf69afd3bb72cf0c729bb3063c6f4498603db17a/jedi-0.19.2.tar.gz", hash = "sha256:4770dc3de41bde3966b02eb84fbcf557fb33cce26ad23da12c742fb50ecb11f0", size = 1231287, upload-time = "2024-11-11T01:41:42.873Z" } wheels = [ @@ -1400,7 +1400,7 @@ name = "jinja2" version = "3.1.6" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "markupsafe" }, + { name = "markupsafe", marker = "sys_platform == 'linux'" }, ] sdist = { url = "https://files.pythonhosted.org/packages/df/bf/f7da0350254c0ed7c72f3e33cef02e048281fec7ecec5f032d4aac52226b/jinja2-3.1.6.tar.gz", hash = "sha256:0137fb05990d35f1275a587e9aee6d56da821fc83491a0fb838183be43f66d6d", size = 245115, upload-time = "2025-03-05T20:05:02.478Z" } wheels = [ @@ -1439,10 +1439,10 @@ name = "jsonschema" version = "4.26.0" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "attrs" }, - { name = "jsonschema-specifications" }, - { name = "referencing" }, - { name = "rpds-py" }, + { name = "attrs", marker = "sys_platform == 'linux'" }, + { name = "jsonschema-specifications", marker = "sys_platform == 'linux'" }, + { name = "referencing", marker = "sys_platform == 'linux'" }, + { name = "rpds-py", marker = "sys_platform == 'linux'" }, ] sdist = { url = "https://files.pythonhosted.org/packages/b3/fc/e067678238fa451312d4c62bf6e6cf5ec56375422aee02f9cb5f909b3047/jsonschema-4.26.0.tar.gz", hash = "sha256:0c26707e2efad8aa1bfc5b7ce170f3fccc2e4918ff85989ba9ffa9facb2be326", size = 366583, upload-time = "2026-01-07T13:41:07.246Z" } wheels = [ @@ -1451,15 +1451,15 @@ wheels = [ [package.optional-dependencies] format-nongpl = [ - { name = "fqdn" }, - { name = "idna" }, - { name = "isoduration" }, - { name = "jsonpointer" }, - { name = "rfc3339-validator" }, - { name = "rfc3986-validator" }, - { name = "rfc3987-syntax" }, - { name = "uri-template" }, - { name = "webcolors" }, + { name = "fqdn", marker = "sys_platform == 'linux'" }, + { name = "idna", marker = "sys_platform == 'linux'" }, + { name = "isoduration", marker = "sys_platform == 'linux'" }, + { name = "jsonpointer", marker = "sys_platform == 'linux'" }, + { name = "rfc3339-validator", marker = "sys_platform == 'linux'" }, + { name = "rfc3986-validator", marker = "sys_platform == 'linux'" }, + { name = "rfc3987-syntax", marker = "sys_platform == 'linux'" }, + { name = "uri-template", marker = "sys_platform == 'linux'" }, + { name = "webcolors", marker = "sys_platform == 'linux'" }, ] [[package]] @@ -1467,7 +1467,7 @@ name = "jsonschema-specifications" version = "2025.9.1" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "referencing" }, + { name = "referencing", marker = "sys_platform == 'linux'" }, ] sdist = { url = "https://files.pythonhosted.org/packages/19/74/a633ee74eb36c44aa6d1095e7cc5569bebf04342ee146178e2d36600708b/jsonschema_specifications-2025.9.1.tar.gz", hash = "sha256:b540987f239e745613c7a9176f3edb72b832a4ac465cf02712288397832b5e8d", size = 32855, upload-time = "2025-09-08T01:34:59.186Z" } wheels = [ @@ -1479,8 +1479,8 @@ name = "jupyter-builder" version = "1.1.0" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "jupyter-core" }, - { name = "traitlets" }, + { name = "jupyter-core", marker = "sys_platform == 'linux'" }, + { name = "traitlets", marker = "sys_platform == 'linux'" }, ] sdist = { url = "https://files.pythonhosted.org/packages/0d/df/db5efc4e28803a1421350445e53d85ec571a4e6928e3524ccc39f4e16584/jupyter_builder-1.1.0.tar.gz", hash = "sha256:b996e8af616900f18724fa34883169d869be2205497940bec78a3a1031eb897d", size = 971142, upload-time = "2026-07-11T07:24:02.4Z" } wheels = [ @@ -1492,11 +1492,11 @@ name = "jupyter-client" version = "8.8.0" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "jupyter-core" }, - { name = "python-dateutil" }, - { name = "pyzmq" }, - { name = "tornado" }, - { name = "traitlets" }, + { name = "jupyter-core", marker = "sys_platform == 'linux'" }, + { name = "python-dateutil", marker = "sys_platform == 'linux'" }, + { name = "pyzmq", marker = "sys_platform == 'linux'" }, + { name = "tornado", marker = "sys_platform == 'linux'" }, + { name = "traitlets", marker = "sys_platform == 'linux'" }, ] sdist = { url = "https://files.pythonhosted.org/packages/05/e4/ba649102a3bc3fbca54e7239fb924fd434c766f855693d86de0b1f2bec81/jupyter_client-8.8.0.tar.gz", hash = "sha256:d556811419a4f2d96c869af34e854e3f059b7cc2d6d01a9cd9c85c267691be3e", size = 348020, upload-time = "2026-01-08T13:55:47.938Z" } wheels = [ @@ -1508,8 +1508,8 @@ name = "jupyter-core" version = "5.9.1" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "platformdirs" }, - { name = "traitlets" }, + { name = "platformdirs", marker = "sys_platform == 'linux'" }, + { name = "traitlets", marker = "sys_platform == 'linux'" }, ] sdist = { url = "https://files.pythonhosted.org/packages/02/49/9d1284d0dc65e2c757b74c6687b6d319b02f822ad039e5c512df9194d9dd/jupyter_core-5.9.1.tar.gz", hash = "sha256:4d09aaff303b9566c3ce657f580bd089ff5c91f5f89cf7d8846c3cdf465b5508", size = 89814, upload-time = "2025-10-16T19:19:18.444Z" } wheels = [ @@ -1521,14 +1521,14 @@ name = "jupyter-events" version = "0.12.1" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "jsonschema", extra = ["format-nongpl"] }, - { name = "packaging" }, - { name = "python-json-logger" }, - { name = "pyyaml" }, - { name = "referencing" }, - { name = "rfc3339-validator" }, - { name = "rfc3986-validator" }, - { name = "traitlets" }, + { name = "jsonschema", extra = ["format-nongpl"], marker = "sys_platform == 'linux'" }, + { name = "packaging", marker = "sys_platform == 'linux'" }, + { name = "python-json-logger", marker = "sys_platform == 'linux'" }, + { name = "pyyaml", marker = "sys_platform == 'linux'" }, + { name = "referencing", marker = "sys_platform == 'linux'" }, + { name = "rfc3339-validator", marker = "sys_platform == 'linux'" }, + { name = "rfc3986-validator", marker = "sys_platform == 'linux'" }, + { name = "traitlets", marker = "sys_platform == 'linux'" }, ] sdist = { url = "https://files.pythonhosted.org/packages/18/f8/475c4241b2b75af0deaae453ed003c6c851766dbc44d332d8baf245dc931/jupyter_events-0.12.1.tar.gz", hash = "sha256:faff25f77218335752f35f23c5fe6e4a392a7bd99a5939ccb9b8fbf594636cf3", size = 62854, upload-time = "2026-04-20T23:17:50.66Z" } wheels = [ @@ -1540,7 +1540,7 @@ name = "jupyter-lsp" version = "2.3.1" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "jupyter-server" }, + { name = "jupyter-server", marker = "sys_platform == 'linux'" }, ] sdist = { url = "https://files.pythonhosted.org/packages/36/ff/1e4a61f5170a9a1d978f3ac3872449de6c01fc71eaf89657824c878b1549/jupyter_lsp-2.3.1.tar.gz", hash = "sha256:fdf8a4aa7d85813976d6e29e95e6a2c8f752701f926f2715305249a3829805a6", size = 55677, upload-time = "2026-04-02T08:10:06.749Z" } wheels = [ @@ -1552,23 +1552,23 @@ name = "jupyter-server" version = "2.20.0" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "anyio" }, - { name = "argon2-cffi" }, - { name = "jinja2" }, - { name = "jupyter-client" }, - { name = "jupyter-core" }, - { name = "jupyter-events" }, - { name = "jupyter-server-terminals" }, - { name = "nbconvert" }, - { name = "nbformat" }, - { name = "packaging" }, - { name = "prometheus-client" }, - { name = "pyzmq" }, - { name = "send2trash" }, - { name = "terminado" }, - { name = "tornado" }, - { name = "traitlets" }, - { name = "websocket-client" }, + { name = "anyio", marker = "sys_platform == 'linux'" }, + { name = "argon2-cffi", marker = "sys_platform == 'linux'" }, + { name = "jinja2", marker = "sys_platform == 'linux'" }, + { name = "jupyter-client", marker = "sys_platform == 'linux'" }, + { name = "jupyter-core", marker = "sys_platform == 'linux'" }, + { name = "jupyter-events", marker = "sys_platform == 'linux'" }, + { name = "jupyter-server-terminals", marker = "sys_platform == 'linux'" }, + { name = "nbconvert", marker = "sys_platform == 'linux'" }, + { name = "nbformat", marker = "sys_platform == 'linux'" }, + { name = "packaging", marker = "sys_platform == 'linux'" }, + { name = "prometheus-client", marker = "sys_platform == 'linux'" }, + { name = "pyzmq", marker = "sys_platform == 'linux'" }, + { name = "send2trash", marker = "sys_platform == 'linux'" }, + { name = "terminado", marker = "sys_platform == 'linux'" }, + { name = "tornado", marker = "sys_platform == 'linux'" }, + { name = "traitlets", marker = "sys_platform == 'linux'" }, + { name = "websocket-client", marker = "sys_platform == 'linux'" }, ] sdist = { url = "https://files.pythonhosted.org/packages/6b/dc/db3a582633170186f8c8b31298d7eb26ad0eb031a1f53476c258b64eed05/jupyter_server-2.20.0.tar.gz", hash = "sha256:b5778ba337d8015a3dc2b80803ecdd5ac18d3797fddf61a50ea5fb472b4ebe14", size = 756523, upload-time = "2026-06-17T12:09:09.435Z" } wheels = [ @@ -1580,7 +1580,7 @@ name = "jupyter-server-terminals" version = "0.5.4" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "terminado" }, + { name = "terminado", marker = "sys_platform == 'linux'" }, ] sdist = { url = "https://files.pythonhosted.org/packages/f4/a7/bcd0a9b0cbba88986fe944aaaf91bfda603e5a50bda8ed15123f381a3b2f/jupyter_server_terminals-0.5.4.tar.gz", hash = "sha256:bbda128ed41d0be9020349f9f1f2a4ab9952a73ed5f5ac9f1419794761fb87f5", size = 31770, upload-time = "2026-01-14T16:53:20.213Z" } wheels = [ @@ -1592,19 +1592,19 @@ name = "jupyterlab" version = "4.6.1" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "async-lru" }, - { name = "httpx" }, - { name = "ipykernel" }, - { name = "jinja2" }, - { name = "jupyter-builder" }, - { name = "jupyter-core" }, - { name = "jupyter-lsp" }, - { name = "jupyter-server" }, - { name = "jupyterlab-server" }, - { name = "notebook-shim" }, - { name = "packaging" }, - { name = "tornado" }, - { name = "traitlets" }, + { name = "async-lru", marker = "sys_platform == 'linux'" }, + { name = "httpx", marker = "sys_platform == 'linux'" }, + { name = "ipykernel", marker = "sys_platform == 'linux'" }, + { name = "jinja2", marker = "sys_platform == 'linux'" }, + { name = "jupyter-builder", marker = "sys_platform == 'linux'" }, + { name = "jupyter-core", marker = "sys_platform == 'linux'" }, + { name = "jupyter-lsp", marker = "sys_platform == 'linux'" }, + { name = "jupyter-server", marker = "sys_platform == 'linux'" }, + { name = "jupyterlab-server", marker = "sys_platform == 'linux'" }, + { name = "notebook-shim", marker = "sys_platform == 'linux'" }, + { name = "packaging", marker = "sys_platform == 'linux'" }, + { name = "tornado", marker = "sys_platform == 'linux'" }, + { name = "traitlets", marker = "sys_platform == 'linux'" }, ] sdist = { url = "https://files.pythonhosted.org/packages/bc/2a/d6af53bfd45a43a5bfe7e40ba47ee7a8921a807daf4bb708e3a295bbb54d/jupyterlab-4.6.1.tar.gz", hash = "sha256:75315982ed28427edaa62bb85eadb5105e4043a757643c910efd787fe6ed0837", size = 28179125, upload-time = "2026-06-29T12:48:45.402Z" } wheels = [ @@ -1625,13 +1625,13 @@ name = "jupyterlab-server" version = "2.28.0" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "babel" }, - { name = "jinja2" }, - { name = "json5" }, - { name = "jsonschema" }, - { name = "jupyter-server" }, - { name = "packaging" }, - { name = "requests" }, + { name = "babel", marker = "sys_platform == 'linux'" }, + { name = "jinja2", marker = "sys_platform == 'linux'" }, + { name = "json5", marker = "sys_platform == 'linux'" }, + { name = "jsonschema", marker = "sys_platform == 'linux'" }, + { name = "jupyter-server", marker = "sys_platform == 'linux'" }, + { name = "packaging", marker = "sys_platform == 'linux'" }, + { name = "requests", marker = "sys_platform == 'linux'" }, ] sdist = { url = "https://files.pythonhosted.org/packages/d6/2c/90153f189e421e93c4bb4f9e3f59802a1f01abd2ac5cf40b152d7f735232/jupyterlab_server-2.28.0.tar.gz", hash = "sha256:35baa81898b15f93573e2deca50d11ac0ae407ebb688299d3a5213265033712c", size = 76996, upload-time = "2025-10-22T13:59:18.37Z" } wheels = [ @@ -1643,11 +1643,11 @@ name = "keyring" version = "25.7.0" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "jaraco-classes" }, - { name = "jaraco-context" }, - { name = "jaraco-functools" }, - { name = "jeepney" }, - { name = "secretstorage" }, + { name = "jaraco-classes", marker = "sys_platform == 'linux'" }, + { name = "jaraco-context", marker = "sys_platform == 'linux'" }, + { name = "jaraco-functools", marker = "sys_platform == 'linux'" }, + { name = "jeepney", marker = "sys_platform == 'linux'" }, + { name = "secretstorage", marker = "sys_platform == 'linux'" }, ] sdist = { url = "https://files.pythonhosted.org/packages/43/4b/674af6ef2f97d56f0ab5153bf0bfa28ccb6c3ed4d1babf4305449668807b/keyring-25.7.0.tar.gz", hash = "sha256:fe01bd85eb3f8fb3dd0405defdeac9a5b4f6f0439edbb3149577f244a2e8245b", size = 63516, upload-time = "2025-11-16T16:26:09.482Z" } wheels = [ @@ -1736,7 +1736,7 @@ name = "lazy-loader" version = "0.5" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "packaging" }, + { name = "packaging", marker = "sys_platform == 'linux'" }, ] sdist = { url = "https://files.pythonhosted.org/packages/49/ac/21a1f8aa3777f5658576777ea76bfb124b702c520bbe90edf4ae9915eafa/lazy_loader-0.5.tar.gz", hash = "sha256:717f9179a0dbed357012ddad50a5ad3d5e4d9a0b8712680d4e687f5e6e6ed9b3", size = 15294, upload-time = "2026-03-06T15:45:09.054Z" } wheels = [ @@ -1773,8 +1773,8 @@ name = "lsstdesc-coord" version = "1.3.1" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "future" }, - { name = "numpy" }, + { name = "future", marker = "sys_platform == 'linux'" }, + { name = "numpy", marker = "sys_platform == 'linux'" }, ] sdist = { url = "https://files.pythonhosted.org/packages/b8/e0/6806df4cfa54927a2d8e425407611b4fc031dd125bc952b4a31deb743305/lsstdesc_coord-1.3.1.tar.gz", hash = "sha256:60f878c29e1f30a9b50bf60dca3c466dc9cfb2cbc71f0a27c575ced969de57ab", size = 41647, upload-time = "2026-02-13T18:37:32.611Z" } wheels = [ @@ -1846,7 +1846,7 @@ name = "markdown-it-py" version = "4.2.0" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "mdurl" }, + { name = "mdurl", marker = "sys_platform == 'linux'" }, ] sdist = { url = "https://files.pythonhosted.org/packages/06/ff/7841249c247aa650a76b9ee4bbaeae59370dc8bfd2f6c01f3630c35eb134/markdown_it_py-4.2.0.tar.gz", hash = "sha256:04a21681d6fbb623de53f6f364d352309d4094dd4194040a10fd51833e418d49", size = 82454, upload-time = "2026-05-07T12:08:28.36Z" } wheels = [ @@ -1896,15 +1896,15 @@ name = "matplotlib" version = "3.11.0" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "contourpy" }, - { name = "cycler" }, - { name = "fonttools" }, - { name = "kiwisolver" }, - { name = "numpy" }, - { name = "packaging" }, - { name = "pillow" }, - { name = "pyparsing" }, - { name = "python-dateutil" }, + { name = "contourpy", marker = "sys_platform == 'linux'" }, + { name = "cycler", marker = "sys_platform == 'linux'" }, + { name = "fonttools", marker = "sys_platform == 'linux'" }, + { name = "kiwisolver", marker = "sys_platform == 'linux'" }, + { name = "numpy", marker = "sys_platform == 'linux'" }, + { name = "packaging", marker = "sys_platform == 'linux'" }, + { name = "pillow", marker = "sys_platform == 'linux'" }, + { name = "pyparsing", marker = "sys_platform == 'linux'" }, + { name = "python-dateutil", marker = "sys_platform == 'linux'" }, ] sdist = { url = "https://files.pythonhosted.org/packages/1f/24/080c99d223d158d3a8902769269ab6da5b50f7a0e6e072513907e02b7a6c/matplotlib-3.11.0.tar.gz", hash = "sha256:68c0c7be01b30dcca3638934f7f591df73401235cbdbf0d1ab1c71e7db7f8b57", size = 33251176, upload-time = "2026-06-12T02:29:15.508Z" } wheels = [ @@ -1930,7 +1930,7 @@ name = "matplotlib-inline" version = "0.2.1" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "traitlets" }, + { name = "traitlets", marker = "sys_platform == 'linux'" }, ] sdist = { url = "https://files.pythonhosted.org/packages/c7/74/97e72a36efd4ae2bccb3463284300f8953f199b5ffbc04cbbb0ec78f74b1/matplotlib_inline-0.2.1.tar.gz", hash = "sha256:e1ee949c340d771fc39e241ea75683deb94762c8fa5f2927ec57c83c4dffa9fe", size = 8110, upload-time = "2025-10-23T09:00:22.126Z" } wheels = [ @@ -1942,11 +1942,11 @@ name = "mccd" version = "1.2.4" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "astropy" }, - { name = "modopt" }, - { name = "numpy" }, - { name = "python-pysap" }, - { name = "scipy" }, + { name = "astropy", marker = "sys_platform == 'linux'" }, + { name = "modopt", marker = "sys_platform == 'linux'" }, + { name = "numpy", marker = "sys_platform == 'linux'" }, + { name = "python-pysap", marker = "sys_platform == 'linux'" }, + { name = "scipy", marker = "sys_platform == 'linux'" }, ] sdist = { url = "https://files.pythonhosted.org/packages/77/b4/2d5618bff92bcc1b928dcc356cbce19cd4ade689d046ba0267da10247f38/mccd-1.2.4.tar.gz", hash = "sha256:e146c84867f4f97e58a0d3de6ead25feceb46f58a1a24e29d102007723e8719f", size = 75762, upload-time = "2023-02-17T19:09:17.039Z" } wheels = [ @@ -1958,7 +1958,7 @@ name = "mdit-py-plugins" version = "0.6.1" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "markdown-it-py" }, + { name = "markdown-it-py", marker = "sys_platform == 'linux'" }, ] sdist = { url = "https://files.pythonhosted.org/packages/59/fc/f8d0863f8862f25602c0404d75568e89fb6b4109804645e5cdfb1be5cf56/mdit_py_plugins-0.6.1.tar.gz", hash = "sha256:a2bca0f039f39dbd35fb74ae1b5f998608c437463371f0ff7f49a19a17a114d0", size = 56114, upload-time = "2026-05-13T09:03:38.91Z" } wheels = [ @@ -1988,10 +1988,10 @@ name = "modopt" version = "1.7.2" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "importlib-metadata" }, - { name = "numpy" }, - { name = "scipy" }, - { name = "tqdm" }, + { name = "importlib-metadata", marker = "sys_platform == 'linux'" }, + { name = "numpy", marker = "sys_platform == 'linux'" }, + { name = "scipy", marker = "sys_platform == 'linux'" }, + { name = "tqdm", marker = "sys_platform == 'linux'" }, ] sdist = { url = "https://files.pythonhosted.org/packages/4d/cf/7665c4990b8623b9e27733edd17a69c63e2d35c5f05d1a253d5ed2f98e52/modopt-1.7.2.tar.gz", hash = "sha256:d5e8edd935b813c3677beeed3245ef4894e7ac09e180150368eda044914488b4", size = 778069, upload-time = "2024-04-12T10:22:11.24Z" } wheels = [ @@ -2041,12 +2041,12 @@ name = "myst-parser" version = "5.1.0" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "docutils" }, - { name = "jinja2" }, - { name = "markdown-it-py" }, - { name = "mdit-py-plugins" }, - { name = "pyyaml" }, - { name = "sphinx" }, + { name = "docutils", marker = "sys_platform == 'linux'" }, + { name = "jinja2", marker = "sys_platform == 'linux'" }, + { name = "markdown-it-py", marker = "sys_platform == 'linux'" }, + { name = "mdit-py-plugins", marker = "sys_platform == 'linux'" }, + { name = "pyyaml", marker = "sys_platform == 'linux'" }, + { name = "sphinx", marker = "sys_platform == 'linux'" }, ] sdist = { url = "https://files.pythonhosted.org/packages/21/dc/603751677fff302f34396e206b610f556a59d7fe58b9a2145f54e96b48e8/myst_parser-5.1.0.tar.gz", hash = "sha256:ab69322dc6719dcc7f296479dbb70181b66df6ed315064f92dbc85c0e1bf2f02", size = 101182, upload-time = "2026-05-13T09:38:19.361Z" } wheels = [ @@ -2058,10 +2058,10 @@ name = "nbclient" version = "0.10.4" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "jupyter-client" }, - { name = "jupyter-core" }, - { name = "nbformat" }, - { name = "traitlets" }, + { name = "jupyter-client", marker = "sys_platform == 'linux'" }, + { name = "jupyter-core", marker = "sys_platform == 'linux'" }, + { name = "nbformat", marker = "sys_platform == 'linux'" }, + { name = "traitlets", marker = "sys_platform == 'linux'" }, ] sdist = { url = "https://files.pythonhosted.org/packages/56/91/1c1d5a4b9a9ebba2b4e32b8c852c2975c872aec1fe42ab5e516b2cecd193/nbclient-0.10.4.tar.gz", hash = "sha256:1e54091b16e6da39e297b0ece3e10f6f29f4ac4e8ee515d29f8a7099bd6553c9", size = 62554, upload-time = "2025-12-23T07:45:46.369Z" } wheels = [ @@ -2073,20 +2073,20 @@ name = "nbconvert" version = "7.17.1" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "beautifulsoup4" }, - { name = "bleach", extra = ["css"] }, - { name = "defusedxml" }, - { name = "jinja2" }, - { name = "jupyter-core" }, - { name = "jupyterlab-pygments" }, - { name = "markupsafe" }, - { name = "mistune" }, - { name = "nbclient" }, - { name = "nbformat" }, - { name = "packaging" }, - { name = "pandocfilters" }, - { name = "pygments" }, - { name = "traitlets" }, + { name = "beautifulsoup4", marker = "sys_platform == 'linux'" }, + { name = "bleach", extra = ["css"], marker = "sys_platform == 'linux'" }, + { name = "defusedxml", marker = "sys_platform == 'linux'" }, + { name = "jinja2", marker = "sys_platform == 'linux'" }, + { name = "jupyter-core", marker = "sys_platform == 'linux'" }, + { name = "jupyterlab-pygments", marker = "sys_platform == 'linux'" }, + { name = "markupsafe", marker = "sys_platform == 'linux'" }, + { name = "mistune", marker = "sys_platform == 'linux'" }, + { name = "nbclient", marker = "sys_platform == 'linux'" }, + { name = "nbformat", marker = "sys_platform == 'linux'" }, + { name = "packaging", marker = "sys_platform == 'linux'" }, + { name = "pandocfilters", marker = "sys_platform == 'linux'" }, + { name = "pygments", marker = "sys_platform == 'linux'" }, + { name = "traitlets", marker = "sys_platform == 'linux'" }, ] sdist = { url = "https://files.pythonhosted.org/packages/01/b1/708e53fe2e429c103c6e6e159106bcf0357ac41aa4c28772bd8402339051/nbconvert-7.17.1.tar.gz", hash = "sha256:34d0d0a7e73ce3cbab6c5aae8f4f468797280b01fd8bd2ca746da8569eddd7d2", size = 865311, upload-time = "2026-04-08T00:44:14.914Z" } wheels = [ @@ -2098,10 +2098,10 @@ name = "nbformat" version = "5.10.4" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "fastjsonschema" }, - { name = "jsonschema" }, - { name = "jupyter-core" }, - { name = "traitlets" }, + { name = "fastjsonschema", marker = "sys_platform == 'linux'" }, + { name = "jsonschema", marker = "sys_platform == 'linux'" }, + { name = "jupyter-core", marker = "sys_platform == 'linux'" }, + { name = "traitlets", marker = "sys_platform == 'linux'" }, ] sdist = { url = "https://files.pythonhosted.org/packages/6d/fd/91545e604bc3dad7dca9ed03284086039b294c6b3d75c0d2fa45f9e9caf3/nbformat-5.10.4.tar.gz", hash = "sha256:322168b14f937a5d11362988ecac2a4952d3d8e3a2cbeb2319584631226d5b3a", size = 142749, upload-time = "2024-04-04T11:20:37.371Z" } wheels = [ @@ -2162,9 +2162,9 @@ name = "nibabel" version = "5.4.2" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "numpy" }, - { name = "packaging" }, - { name = "typing-extensions", marker = "python_full_version < '3.13'" }, + { name = "numpy", marker = "sys_platform == 'linux'" }, + { name = "packaging", marker = "sys_platform == 'linux'" }, + { name = "typing-extensions", marker = "python_full_version < '3.13' and sys_platform == 'linux'" }, ] sdist = { url = "https://files.pythonhosted.org/packages/a3/01/3d2cc510c616bc8e27be17a063070d9126f69407961594a9ae734ea51121/nibabel-5.4.2.tar.gz", hash = "sha256:d5f4b9076a13178ae7f7acf18c8dbd503ee1c4d5c0c23b85df7be87efcbb49da", size = 4663132, upload-time = "2026-03-11T13:31:52.42Z" } wheels = [ @@ -2176,7 +2176,7 @@ name = "notebook-shim" version = "0.2.4" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "jupyter-server" }, + { name = "jupyter-server", marker = "sys_platform == 'linux'" }, ] sdist = { url = "https://files.pythonhosted.org/packages/54/d2/92fa3243712b9a3e8bafaf60aac366da1cada3639ca767ff4b5b3654ec28/notebook_shim-0.2.4.tar.gz", hash = "sha256:b4b2cfa1b65d98307ca24361f5b30fe785b53c3fd07b7a47e89acb5e6ac638cb", size = 13167, upload-time = "2024-02-14T23:35:18.353Z" } wheels = [ @@ -2188,8 +2188,8 @@ name = "numba" version = "0.66.0" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "llvmlite" }, - { name = "numpy" }, + { name = "llvmlite", marker = "sys_platform == 'linux'" }, + { name = "numpy", marker = "sys_platform == 'linux'" }, ] sdist = { url = "https://files.pythonhosted.org/packages/ae/a0/570e3dc53e5602b49108f62a13e529f1eec8bfc7ef37d49c825924dcf546/numba-0.66.0.tar.gz", hash = "sha256:b900e63a0e26c05ea9a6d5a3a5a0a177cb64c5011887bf43edb8c3ed2c38d363", size = 2806181, upload-time = "2026-07-01T23:12:46.36Z" } wheels = [ @@ -2208,8 +2208,8 @@ name = "numcodecs" version = "0.16.5" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "numpy" }, - { name = "typing-extensions" }, + { name = "numpy", marker = "sys_platform == 'linux'" }, + { name = "typing-extensions", marker = "sys_platform == 'linux'" }, ] sdist = { url = "https://files.pythonhosted.org/packages/44/bd/8a391e7c356366224734efd24da929cc4796fff468bfb179fe1af6548535/numcodecs-0.16.5.tar.gz", hash = "sha256:0d0fb60852f84c0bd9543cc4d2ab9eefd37fc8efcc410acd4777e62a1d300318", size = 6276387, upload-time = "2025-11-21T02:49:48.986Z" } wheels = [ @@ -2254,7 +2254,7 @@ name = "numpydoc" version = "1.10.0" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "sphinx" }, + { name = "sphinx", marker = "sys_platform == 'linux'" }, ] sdist = { url = "https://files.pythonhosted.org/packages/e9/3c/dfccc9e7dee357fb2aa13c3890d952a370dd0ed071e0f7ed62ed0df567c1/numpydoc-1.10.0.tar.gz", hash = "sha256:3f7970f6eee30912260a6b31ac72bba2432830cd6722569ec17ee8d3ef5ffa01", size = 94027, upload-time = "2025-12-02T16:39:12.937Z" } wheels = [ @@ -2275,8 +2275,8 @@ name = "pandas" version = "3.0.3" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "numpy" }, - { name = "python-dateutil" }, + { name = "numpy", marker = "sys_platform == 'linux'" }, + { name = "python-dateutil", marker = "sys_platform == 'linux'" }, ] sdist = { url = "https://files.pythonhosted.org/packages/f8/87/4341c6252d1c47b08768c3d25ac487362bf403f0313ddae4a2a26c9b1b4c/pandas-3.0.3.tar.gz", hash = "sha256:696a4a00a2a2a35d4e5deb3fc946641b96c944f02230e4f76137fe35d806c4fc", size = 4651414, upload-time = "2026-05-11T18:54:29.21Z" } wheels = [ @@ -2325,8 +2325,8 @@ name = "partd" version = "1.4.2" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "locket" }, - { name = "toolz" }, + { name = "locket", marker = "sys_platform == 'linux'" }, + { name = "toolz", marker = "sys_platform == 'linux'" }, ] sdist = { url = "https://files.pythonhosted.org/packages/b2/3a/3f06f34820a31257ddcabdfafc2672c5816be79c7e353b02c1f318daa7d4/partd-1.4.2.tar.gz", hash = "sha256:d022c33afbdc8405c226621b015e8067888173d85f7f5ecebb3cafed9a20f02c", size = 21029, upload-time = "2024-05-06T19:51:41.945Z" } wheels = [ @@ -2338,7 +2338,7 @@ name = "pexpect" version = "4.9.0" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "ptyprocess" }, + { name = "ptyprocess", marker = "sys_platform == 'linux'" }, ] sdist = { url = "https://files.pythonhosted.org/packages/42/92/cc564bf6381ff43ce1f4d06852fc19a2f11d180f23dc32d9588bee2f149d/pexpect-4.9.0.tar.gz", hash = "sha256:ee7d41123f3c9911050ea2c2dac107568dc43b2d3b0c7557a33212c398ead30f", size = 166450, upload-time = "2023-11-25T09:07:26.339Z" } wheels = [ @@ -2394,11 +2394,11 @@ name = "pims" version = "0.7" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "imageio" }, - { name = "numpy" }, - { name = "packaging" }, - { name = "slicerator" }, - { name = "tifffile" }, + { name = "imageio", marker = "sys_platform == 'linux'" }, + { name = "numpy", marker = "sys_platform == 'linux'" }, + { name = "packaging", marker = "sys_platform == 'linux'" }, + { name = "slicerator", marker = "sys_platform == 'linux'" }, + { name = "tifffile", marker = "sys_platform == 'linux'" }, ] sdist = { url = "https://files.pythonhosted.org/packages/b8/02/5bf3639f5b77e9b183011c08541c5039ba3d04f5316c70312b48a8e003a9/pims-0.7.tar.gz", hash = "sha256:55907a4c301256086d2aa4e34a5361b9109f24e375c2071e1117b9491e82946b", size = 87779, upload-time = "2024-06-10T19:20:42.842Z" } @@ -2425,7 +2425,7 @@ name = "progressbar2" version = "4.5.0" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "python-utils" }, + { name = "python-utils", marker = "sys_platform == 'linux'" }, ] sdist = { url = "https://files.pythonhosted.org/packages/19/24/3587e795fc590611434e4bcb9fbe0c3dddb5754ce1a20edfd86c587c0004/progressbar2-4.5.0.tar.gz", hash = "sha256:6662cb624886ed31eb94daf61e27583b5144ebc7383a17bae076f8f4f59088fb", size = 101449, upload-time = "2024-08-28T22:50:12.391Z" } wheels = [ @@ -2446,7 +2446,7 @@ name = "prompt-toolkit" version = "3.0.52" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "wcwidth" }, + { name = "wcwidth", marker = "sys_platform == 'linux'" }, ] sdist = { url = "https://files.pythonhosted.org/packages/a1/96/06e01a7b38dce6fe1db213e061a4602dd6032a8a97ef6c1a862537732421/prompt_toolkit-3.0.52.tar.gz", hash = "sha256:28cde192929c8e7321de85de1ddbe736f1375148b02f2e17edd840042b1be855", size = 434198, upload-time = "2025-08-27T15:24:02.057Z" } wheels = [ @@ -2547,8 +2547,8 @@ name = "pybtex" version = "0.26.1" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "latexcodec" }, - { name = "pyyaml" }, + { name = "latexcodec", marker = "sys_platform == 'linux'" }, + { name = "pyyaml", marker = "sys_platform == 'linux'" }, ] sdist = { url = "https://files.pythonhosted.org/packages/4d/f5/f30da9c93f0fa6d619332b2f69597219b625f35780473a05164a9981fd9a/pybtex-0.26.1.tar.gz", hash = "sha256:2e5543bea424e60e9e42eef70bff597be48649d8f68ba061a7a092b2477d5464", size = 692991, upload-time = "2026-04-03T13:05:39.014Z" } wheels = [ @@ -2560,8 +2560,8 @@ name = "pybtex-docutils" version = "1.0.3" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "docutils" }, - { name = "pybtex" }, + { name = "docutils", marker = "sys_platform == 'linux'" }, + { name = "pybtex", marker = "sys_platform == 'linux'" }, ] sdist = { url = "https://files.pythonhosted.org/packages/7e/84/796ea94d26188a853660f81bded39f8de4cfe595130aef0dea1088705a11/pybtex-docutils-1.0.3.tar.gz", hash = "sha256:3a7ebdf92b593e00e8c1c538aa9a20bca5d92d84231124715acc964d51d93c6b", size = 18348, upload-time = "2023-08-22T18:47:54.833Z" } wheels = [ @@ -2573,10 +2573,10 @@ name = "pyccl" version = "3.3.3" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "numpy" }, - { name = "packaging" }, - { name = "pyyaml" }, - { name = "scipy" }, + { name = "numpy", marker = "sys_platform == 'linux'" }, + { name = "packaging", marker = "sys_platform == 'linux'" }, + { name = "pyyaml", marker = "sys_platform == 'linux'" }, + { name = "scipy", marker = "sys_platform == 'linux'" }, ] sdist = { url = "https://files.pythonhosted.org/packages/6a/b5/8bc08fd09c5a37b888978ba1bcb0769a30f08d89d526d786e5434d7f5c68/pyccl-3.3.3.tar.gz", hash = "sha256:a55f9f3b6fd57af291294601e22e0c4b21c46b9bba6c659c63b1dbe288dc0824", size = 16783008, upload-time = "2026-04-08T19:06:56.861Z" } @@ -2594,10 +2594,10 @@ name = "pydantic" version = "2.13.3" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "annotated-types" }, - { name = "pydantic-core" }, - { name = "typing-extensions" }, - { name = "typing-inspection" }, + { name = "annotated-types", marker = "sys_platform == 'linux'" }, + { name = "pydantic-core", marker = "sys_platform == 'linux'" }, + { name = "typing-extensions", marker = "sys_platform == 'linux'" }, + { name = "typing-inspection", marker = "sys_platform == 'linux'" }, ] sdist = { url = "https://files.pythonhosted.org/packages/d9/e4/40d09941a2cebcb20609b86a559817d5b9291c49dd6f8c87e5feffbe703a/pydantic-2.13.3.tar.gz", hash = "sha256:af09e9d1d09f4e7fe37145c1f577e1d61ceb9a41924bf0094a36506285d0a84d", size = 844068, upload-time = "2026-04-20T14:46:43.632Z" } wheels = [ @@ -2609,7 +2609,7 @@ name = "pydantic-core" version = "2.46.3" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "typing-extensions" }, + { name = "typing-extensions", marker = "sys_platform == 'linux'" }, ] sdist = { url = "https://files.pythonhosted.org/packages/2a/ef/f7abb56c49382a246fd2ce9c799691e3c3e7175ec74b14d99e798bcddb1a/pydantic_core-2.46.3.tar.gz", hash = "sha256:41c178f65b8c29807239d47e6050262eb6bf84eb695e41101e62e38df4a5bc2c", size = 471412, upload-time = "2026-04-20T14:40:56.672Z" } wheels = [ @@ -2662,9 +2662,9 @@ name = "pydantic-settings" version = "2.14.2" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "pydantic" }, - { name = "python-dotenv" }, - { name = "typing-inspection" }, + { name = "pydantic", marker = "sys_platform == 'linux'" }, + { name = "python-dotenv", marker = "sys_platform == 'linux'" }, + { name = "typing-inspection", marker = "sys_platform == 'linux'" }, ] sdist = { url = "https://files.pythonhosted.org/packages/5c/b5/8f48e906c3e0205276e8bd8cb7512217a87b2685304d64be27cad5b3019f/pydantic_settings-2.14.2.tar.gz", hash = "sha256:c19dd64b19097f1de80184f0cc7b0272a13ae6e170cbf240a3e27e381ed14a5f", size = 237700, upload-time = "2026-06-19T13:44:56.324Z" } wheels = [ @@ -2676,13 +2676,13 @@ name = "pydata-sphinx-theme" version = "0.16.1" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "accessible-pygments" }, - { name = "babel" }, - { name = "beautifulsoup4" }, - { name = "docutils" }, - { name = "pygments" }, - { name = "sphinx" }, - { name = "typing-extensions" }, + { name = "accessible-pygments", marker = "sys_platform == 'linux'" }, + { name = "babel", marker = "sys_platform == 'linux'" }, + { name = "beautifulsoup4", marker = "sys_platform == 'linux'" }, + { name = "docutils", marker = "sys_platform == 'linux'" }, + { name = "pygments", marker = "sys_platform == 'linux'" }, + { name = "sphinx", marker = "sys_platform == 'linux'" }, + { name = "typing-extensions", marker = "sys_platform == 'linux'" }, ] sdist = { url = "https://files.pythonhosted.org/packages/00/20/bb50f9de3a6de69e6abd6b087b52fa2418a0418b19597601605f855ad044/pydata_sphinx_theme-0.16.1.tar.gz", hash = "sha256:a08b7f0b7f70387219dc659bff0893a7554d5eb39b59d3b8ef37b8401b7642d7", size = 2412693, upload-time = "2024-12-17T10:53:39.537Z" } wheels = [ @@ -2694,7 +2694,7 @@ name = "pyerfa" version = "2.0.1.5" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "numpy" }, + { name = "numpy", marker = "sys_platform == 'linux'" }, ] sdist = { url = "https://files.pythonhosted.org/packages/71/39/63cc8291b0cf324ae710df41527faf7d331bce573899199d926b3e492260/pyerfa-2.0.1.5.tar.gz", hash = "sha256:17d6b24fe4846c65d5e7d8c362dcb08199dc63b30a236aedd73875cc83e1f6c0", size = 818430, upload-time = "2024-11-11T15:22:30.852Z" } wheels = [ @@ -2717,8 +2717,8 @@ name = "pyopenssl" version = "26.2.0" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "cryptography" }, - { name = "typing-extensions", marker = "python_full_version < '3.13'" }, + { name = "cryptography", marker = "sys_platform == 'linux'" }, + { name = "typing-extensions", marker = "python_full_version < '3.13' and sys_platform == 'linux'" }, ] sdist = { url = "https://files.pythonhosted.org/packages/1a/51/27a5ad5f939d08f690a326ef9582cda7140555180db71695f6fb747d6a36/pyopenssl-26.2.0.tar.gz", hash = "sha256:8c6fcecd1183a7fc897548dfe388b0cdb7f37e018200d8409cf33959dbe35387", size = 182195, upload-time = "2026-05-04T23:06:09.72Z" } wheels = [ @@ -2748,8 +2748,8 @@ name = "pyqt5" version = "5.15.11" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "pyqt5-qt5" }, - { name = "pyqt5-sip" }, + { name = "pyqt5-qt5", marker = "sys_platform == 'linux'" }, + { name = "pyqt5-sip", marker = "sys_platform == 'linux'" }, ] sdist = { url = "https://files.pythonhosted.org/packages/0e/07/c9ed0bd428df6f87183fca565a79fee19fa7c88c7f00a7f011ab4379e77a/PyQt5-5.15.11.tar.gz", hash = "sha256:fda45743ebb4a27b4b1a51c6d8ef455c4c1b5d610c90d2934c7802b5c1557c52", size = 3216775, upload-time = "2024-07-19T08:39:57.756Z" } wheels = [ @@ -2783,8 +2783,8 @@ name = "pyqtgraph" version = "0.14.0" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "colorama" }, - { name = "numpy" }, + { name = "colorama", marker = "sys_platform == 'linux'" }, + { name = "numpy", marker = "sys_platform == 'linux'" }, ] wheels = [ { url = "https://files.pythonhosted.org/packages/32/36/4c242f81fdcbfa4fb62a5645f6af79191f4097a0577bd5460c24f19cc4ef/pyqtgraph-0.14.0-py3-none-any.whl", hash = "sha256:7abb7c3e17362add64f8711b474dffac5e7b0e9245abdf992e9a44119b7aa4f5", size = 1924755, upload-time = "2025-11-16T19:43:22.251Z" }, @@ -2795,10 +2795,10 @@ name = "pytest" version = "9.1.1" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "iniconfig" }, - { name = "packaging" }, - { name = "pluggy" }, - { name = "pygments" }, + { name = "iniconfig", marker = "sys_platform == 'linux'" }, + { name = "packaging", marker = "sys_platform == 'linux'" }, + { name = "pluggy", marker = "sys_platform == 'linux'" }, + { name = "pygments", marker = "sys_platform == 'linux'" }, ] sdist = { url = "https://files.pythonhosted.org/packages/e4/47/b9efed96c114afcfa3c9d3fe98a76a1d14c74a9e266d397cf6eb64be5e01/pytest-9.1.1.tar.gz", hash = "sha256:1088fbde8f2b49d95a549a195707afa7a76a3ce9bcadc26b6d71f0ffda5fe313", size = 1636369, upload-time = "2026-06-19T10:58:32.857Z" } wheels = [ @@ -2810,9 +2810,9 @@ name = "pytest-cov" version = "7.1.0" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "coverage" }, - { name = "pluggy" }, - { name = "pytest" }, + { name = "coverage", marker = "sys_platform == 'linux'" }, + { name = "pluggy", marker = "sys_platform == 'linux'" }, + { name = "pytest", marker = "sys_platform == 'linux'" }, ] sdist = { url = "https://files.pythonhosted.org/packages/b1/51/a849f96e117386044471c8ec2bd6cfebacda285da9525c9106aeb28da671/pytest_cov-7.1.0.tar.gz", hash = "sha256:30674f2b5f6351aa09702a9c8c364f6a01c27aae0c1366ae8016160d1efc56b2", size = 55592, upload-time = "2026-03-21T20:11:16.284Z" } wheels = [ @@ -2824,7 +2824,7 @@ name = "python-dateutil" version = "2.9.0.post0" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "six" }, + { name = "six", marker = "sys_platform == 'linux'" }, ] sdist = { url = "https://files.pythonhosted.org/packages/66/c0/0c8b6ad9f17a802ee498c46e004a0eb49bc148f2fd230864601a86dcf6db/python-dateutil-2.9.0.post0.tar.gz", hash = "sha256:37dd54208da7e1cd875388217d5e00ebd4179249f90fb72437e91a35459a0ad3", size = 342432, upload-time = "2024-03-01T18:36:20.211Z" } wheels = [ @@ -2854,16 +2854,16 @@ name = "python-pysap" version = "0.3.0" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "astropy" }, - { name = "matplotlib" }, - { name = "modopt" }, - { name = "nibabel" }, - { name = "numpy" }, - { name = "progressbar2" }, - { name = "pywavelets" }, - { name = "scikit-image" }, - { name = "scikit-learn" }, - { name = "scipy" }, + { name = "astropy", marker = "sys_platform == 'linux'" }, + { name = "matplotlib", marker = "sys_platform == 'linux'" }, + { name = "modopt", marker = "sys_platform == 'linux'" }, + { name = "nibabel", marker = "sys_platform == 'linux'" }, + { name = "numpy", marker = "sys_platform == 'linux'" }, + { name = "progressbar2", marker = "sys_platform == 'linux'" }, + { name = "pywavelets", marker = "sys_platform == 'linux'" }, + { name = "scikit-image", marker = "sys_platform == 'linux'" }, + { name = "scikit-learn", marker = "sys_platform == 'linux'" }, + { name = "scipy", marker = "sys_platform == 'linux'" }, ] sdist = { url = "https://files.pythonhosted.org/packages/f1/90/29b10f180876a322c7cfbadd2552efef34374dceb618fdc3f48ef792666e/python_pysap-0.3.0.tar.gz", hash = "sha256:55cdfec05eacc410723f31df754b67728224935aef7d4332b89ef6e90f2aab97", size = 775664, upload-time = "2026-01-06T10:12:58.287Z" } @@ -2872,7 +2872,7 @@ name = "python-utils" version = "3.9.1" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "typing-extensions" }, + { name = "typing-extensions", marker = "sys_platform == 'linux'" }, ] sdist = { url = "https://files.pythonhosted.org/packages/13/4c/ef8b7b1046d65c1f18ca31e5235c7d6627ca2b3f389ab1d44a74d22f5cc9/python_utils-3.9.1.tar.gz", hash = "sha256:eb574b4292415eb230f094cbf50ab5ef36e3579b8f09e9f2ba74af70891449a0", size = 35403, upload-time = "2024-11-26T00:38:58.736Z" } wheels = [ @@ -2893,8 +2893,8 @@ name = "pyvo" version = "1.8.1" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "astropy" }, - { name = "requests" }, + { name = "astropy", marker = "sys_platform == 'linux'" }, + { name = "requests", marker = "sys_platform == 'linux'" }, ] sdist = { url = "https://files.pythonhosted.org/packages/d9/33/51077325e08b68d13498ec1a63134f1feef6659ea4ad437649c942cac916/pyvo-1.8.1.tar.gz", hash = "sha256:d3cc60aa3d3416d22c89e465a04dfa9f521085fdd5228cce2cffd2fee3a9e709", size = 2120129, upload-time = "2026-02-12T21:20:41.983Z" } wheels = [ @@ -2906,7 +2906,7 @@ name = "pywavelets" version = "1.9.0" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "numpy" }, + { name = "numpy", marker = "sys_platform == 'linux'" }, ] sdist = { url = "https://files.pythonhosted.org/packages/5a/75/50581633d199812205ea8cdd0f6d52f12a624886b74bf1486335b67f01ff/pywavelets-1.9.0.tar.gz", hash = "sha256:148d12203377772bea452a59211d98649c8ee4a05eff019a9021853a36babdc8", size = 3938340, upload-time = "2025-08-04T16:20:04.978Z" } wheels = [ @@ -2965,7 +2965,7 @@ name = "pyzmq" version = "27.1.0" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "cffi", marker = "implementation_name == 'pypy'" }, + { name = "cffi", marker = "implementation_name == 'pypy' and sys_platform == 'linux'" }, ] sdist = { url = "https://files.pythonhosted.org/packages/04/0b/3c9baedbdf613ecaa7aa07027780b8867f57b6293b6ee50de316c9f3222b/pyzmq-27.1.0.tar.gz", hash = "sha256:ac0765e3d44455adb6ddbf4417dcce460fc40a05978c08efdf2948072f6db540", size = 281750, upload-time = "2025-09-08T23:10:18.157Z" } wheels = [ @@ -2994,7 +2994,7 @@ name = "questionary" version = "2.1.1" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "prompt-toolkit" }, + { name = "prompt-toolkit", marker = "sys_platform == 'linux'" }, ] sdist = { url = "https://files.pythonhosted.org/packages/f6/45/eafb0bba0f9988f6a2520f9ca2df2c82ddfa8d67c95d6625452e97b204a5/questionary-2.1.1.tar.gz", hash = "sha256:3d7e980292bb0107abaa79c68dd3eee3c561b83a0f89ae482860b181c8bd412d", size = 25845, upload-time = "2025-08-28T19:00:20.851Z" } wheels = [ @@ -3006,9 +3006,9 @@ name = "readme-renderer" version = "44.0" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "docutils" }, - { name = "nh3" }, - { name = "pygments" }, + { name = "docutils", marker = "sys_platform == 'linux'" }, + { name = "nh3", marker = "sys_platform == 'linux'" }, + { name = "pygments", marker = "sys_platform == 'linux'" }, ] sdist = { url = "https://files.pythonhosted.org/packages/5a/a9/104ec9234c8448c4379768221ea6df01260cd6c2ce13182d4eac531c8342/readme_renderer-44.0.tar.gz", hash = "sha256:8712034eabbfa6805cacf1402b4eeb2a73028f72d1166d6f5cb7f9c047c5d1e1", size = 32056, upload-time = "2024-07-08T15:00:57.805Z" } wheels = [ @@ -3020,9 +3020,9 @@ name = "referencing" version = "0.37.0" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "attrs" }, - { name = "rpds-py" }, - { name = "typing-extensions", marker = "python_full_version < '3.13'" }, + { name = "attrs", marker = "sys_platform == 'linux'" }, + { name = "rpds-py", marker = "sys_platform == 'linux'" }, + { name = "typing-extensions", marker = "python_full_version < '3.13' and sys_platform == 'linux'" }, ] sdist = { url = "https://files.pythonhosted.org/packages/22/f5/df4e9027acead3ecc63e50fe1e36aca1523e1719559c499951bb4b53188f/referencing-0.37.0.tar.gz", hash = "sha256:44aefc3142c5b842538163acb373e24cce6632bd54bdb01b21ad5863489f50d8", size = 78036, upload-time = "2025-10-13T15:30:48.871Z" } wheels = [ @@ -3034,16 +3034,16 @@ name = "reproject" version = "0.21.0" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "astropy" }, - { name = "astropy-healpix" }, - { name = "dask", extra = ["array"] }, - { name = "dask-image" }, - { name = "fsspec" }, - { name = "numpy" }, - { name = "pillow" }, - { name = "pyavm" }, - { name = "scipy" }, - { name = "zarr" }, + { name = "astropy", marker = "sys_platform == 'linux'" }, + { name = "astropy-healpix", marker = "sys_platform == 'linux'" }, + { name = "dask", extra = ["array"], marker = "sys_platform == 'linux'" }, + { name = "dask-image", marker = "sys_platform == 'linux'" }, + { name = "fsspec", marker = "sys_platform == 'linux'" }, + { name = "numpy", marker = "sys_platform == 'linux'" }, + { name = "pillow", marker = "sys_platform == 'linux'" }, + { name = "pyavm", marker = "sys_platform == 'linux'" }, + { name = "scipy", marker = "sys_platform == 'linux'" }, + { name = "zarr", marker = "sys_platform == 'linux'" }, ] sdist = { url = "https://files.pythonhosted.org/packages/cc/44/6fd820ba336484277a91a2f4808b60d6ec0b9f033f588c237e778f20fe89/reproject-0.21.0.tar.gz", hash = "sha256:01ede715a1993c29431f52ff74189ef30f5e7b2e8b4dc88c1b002145a971dc1c", size = 1622661, upload-time = "2026-06-25T15:11:34.886Z" } wheels = [ @@ -3056,10 +3056,10 @@ name = "requests" version = "2.33.1" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "certifi" }, - { name = "charset-normalizer" }, - { name = "idna" }, - { name = "urllib3" }, + { name = "certifi", marker = "sys_platform == 'linux'" }, + { name = "charset-normalizer", marker = "sys_platform == 'linux'" }, + { name = "idna", marker = "sys_platform == 'linux'" }, + { name = "urllib3", marker = "sys_platform == 'linux'" }, ] sdist = { url = "https://files.pythonhosted.org/packages/5f/a4/98b9c7c6428a668bf7e42ebb7c79d576a1c3c1e3ae2d47e674b468388871/requests-2.33.1.tar.gz", hash = "sha256:18817f8c57c6263968bc123d237e3b8b08ac046f5456bd1e307ee8f4250d3517", size = 134120, upload-time = "2026-03-30T16:09:15.531Z" } wheels = [ @@ -3071,7 +3071,7 @@ name = "requests-toolbelt" version = "1.0.0" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "requests" }, + { name = "requests", marker = "sys_platform == 'linux'" }, ] sdist = { url = "https://files.pythonhosted.org/packages/f3/61/d7545dafb7ac2230c70d38d31cbfe4cc64f7144dc41f6e4e4b78ecd9f5bb/requests-toolbelt-1.0.0.tar.gz", hash = "sha256:7681a0a3d047012b5bdc0ee37d7f8f07ebe76ab08caeccfc3921ce23c88d5bc6", size = 206888, upload-time = "2023-05-01T04:11:33.229Z" } wheels = [ @@ -3083,7 +3083,7 @@ name = "rfc3339-validator" version = "0.1.4" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "six" }, + { name = "six", marker = "sys_platform == 'linux'" }, ] sdist = { url = "https://files.pythonhosted.org/packages/28/ea/a9387748e2d111c3c2b275ba970b735e04e15cdb1eb30693b6b5708c4dbd/rfc3339_validator-0.1.4.tar.gz", hash = "sha256:138a2abdf93304ad60530167e51d2dfb9549521a836871b88d7f4695d0022f6b", size = 5513, upload-time = "2021-05-12T16:37:54.178Z" } wheels = [ @@ -3113,7 +3113,7 @@ name = "rfc3987-syntax" version = "1.1.0" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "lark" }, + { name = "lark", marker = "sys_platform == 'linux'" }, ] sdist = { url = "https://files.pythonhosted.org/packages/2c/06/37c1a5557acf449e8e406a830a05bf885ac47d33270aec454ef78675008d/rfc3987_syntax-1.1.0.tar.gz", hash = "sha256:717a62cbf33cffdd16dfa3a497d81ce48a660ea691b1ddd7be710c22f00b4a0d", size = 14239, upload-time = "2025-07-18T01:05:05.015Z" } wheels = [ @@ -3125,8 +3125,8 @@ name = "rich" version = "15.0.0" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "markdown-it-py" }, - { name = "pygments" }, + { name = "markdown-it-py", marker = "sys_platform == 'linux'" }, + { name = "pygments", marker = "sys_platform == 'linux'" }, ] sdist = { url = "https://files.pythonhosted.org/packages/c0/8f/0722ca900cc807c13a6a0c696dacf35430f72e0ec571c4275d2371fca3e9/rich-15.0.0.tar.gz", hash = "sha256:edd07a4824c6b40189fb7ac9bc4c52536e9780fbbfbddf6f1e2502c31b068c36", size = 230680, upload-time = "2026-04-12T08:24:00.75Z" } wheels = [ @@ -3225,14 +3225,14 @@ name = "scikit-image" version = "0.26.0" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "imageio" }, - { name = "lazy-loader" }, - { name = "networkx" }, - { name = "numpy" }, - { name = "packaging" }, - { name = "pillow" }, - { name = "scipy" }, - { name = "tifffile" }, + { name = "imageio", marker = "sys_platform == 'linux'" }, + { name = "lazy-loader", marker = "sys_platform == 'linux'" }, + { name = "networkx", marker = "sys_platform == 'linux'" }, + { name = "numpy", marker = "sys_platform == 'linux'" }, + { name = "packaging", marker = "sys_platform == 'linux'" }, + { name = "pillow", marker = "sys_platform == 'linux'" }, + { name = "scipy", marker = "sys_platform == 'linux'" }, + { name = "tifffile", marker = "sys_platform == 'linux'" }, ] sdist = { url = "https://files.pythonhosted.org/packages/a1/b4/2528bb43c67d48053a7a649a9666432dc307d66ba02e3a6d5c40f46655df/scikit_image-0.26.0.tar.gz", hash = "sha256:f5f970ab04efad85c24714321fcc91613fcb64ef2a892a13167df2f3e59199fa", size = 22729739, upload-time = "2025-12-20T17:12:21.824Z" } wheels = [ @@ -3263,10 +3263,10 @@ name = "scikit-learn" version = "1.8.0" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "joblib" }, - { name = "numpy" }, - { name = "scipy" }, - { name = "threadpoolctl" }, + { name = "joblib", marker = "sys_platform == 'linux'" }, + { name = "numpy", marker = "sys_platform == 'linux'" }, + { name = "scipy", marker = "sys_platform == 'linux'" }, + { name = "threadpoolctl", marker = "sys_platform == 'linux'" }, ] sdist = { url = "https://files.pythonhosted.org/packages/0e/d4/40988bf3b8e34feec1d0e6a051446b1f66225f8529b9309becaeef62b6c4/scikit_learn-1.8.0.tar.gz", hash = "sha256:9bccbb3b40e3de10351f8f5068e105d0f4083b1a65fa07b6634fbc401a6287fd", size = 7335585, upload-time = "2025-12-10T07:08:53.618Z" } wheels = [ @@ -3287,7 +3287,7 @@ name = "scipy" version = "1.17.1" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "numpy" }, + { name = "numpy", marker = "sys_platform == 'linux'" }, ] sdist = { url = "https://files.pythonhosted.org/packages/7a/97/5a3609c4f8d58b039179648e62dd220f89864f56f7357f5d4f45c29eb2cc/scipy-1.17.1.tar.gz", hash = "sha256:95d8e012d8cb8816c226aef832200b1d45109ed4464303e997c5b13122b297c0", size = 30573822, upload-time = "2026-02-23T00:26:24.851Z" } wheels = [ @@ -3318,8 +3318,8 @@ name = "secretstorage" version = "3.5.0" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "cryptography" }, - { name = "jeepney" }, + { name = "cryptography", marker = "sys_platform == 'linux'" }, + { name = "jeepney", marker = "sys_platform == 'linux'" }, ] sdist = { url = "https://files.pythonhosted.org/packages/1c/03/e834bcd866f2f8a49a85eaff47340affa3bfa391ee9912a952a1faa68c7b/secretstorage-3.5.0.tar.gz", hash = "sha256:f04b8e4689cbce351744d5537bf6b1329c6fc68f91fa666f60a380edddcd11be", size = 19884, upload-time = "2025-11-23T19:02:53.191Z" } wheels = [ @@ -3358,9 +3358,9 @@ name = "sf-tools" version = "2.0.4" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "future" }, - { name = "modopt" }, - { name = "numpy" }, + { name = "future", marker = "sys_platform == 'linux'" }, + { name = "modopt", marker = "sys_platform == 'linux'" }, + { name = "numpy", marker = "sys_platform == 'linux'" }, ] sdist = { url = "https://files.pythonhosted.org/packages/c2/41/6281d12b863867fc7d7db0aeb55db7ec94fb8f35873b9940edeeb3c29d0f/sf_tools-2.0.4.tar.gz", hash = "sha256:607204b7369cb381c02ba95f49f13d2733877a625026fac340dcddcca6700d24", size = 10426, upload-time = "2019-08-22T08:41:46.961Z" } @@ -3369,78 +3369,80 @@ name = "shapepipe" version = "1.1.0" source = { editable = "." } dependencies = [ - { name = "astropy" }, - { name = "astroquery" }, - { name = "canfar" }, - { name = "cs-util" }, - { name = "galsim" }, - { name = "h5py" }, - { name = "joblib" }, - { name = "matplotlib" }, - { name = "mccd" }, - { name = "modopt" }, - { name = "mpi4py" }, - { name = "ngmix" }, - { name = "numba" }, - { name = "numpy" }, - { name = "pandas" }, - { name = "pyqt5" }, - { name = "pyqtgraph" }, - { name = "python-dateutil" }, - { name = "python-pysap" }, - { name = "reproject" }, - { name = "sf-tools" }, - { name = "skaha" }, - { name = "sqlitedict" }, - { name = "termcolor" }, - { name = "tqdm" }, - { name = "vos" }, + { name = "astropy", marker = "sys_platform == 'linux'" }, + { name = "astroquery", marker = "sys_platform == 'linux'" }, + { name = "canfar", marker = "sys_platform == 'linux'" }, + { name = "cs-util", marker = "sys_platform == 'linux'" }, + { name = "galsim", marker = "sys_platform == 'linux'" }, + { name = "h5py", marker = "sys_platform == 'linux'" }, + { name = "healsparse", marker = "sys_platform == 'linux'" }, + { name = "hpgeom", marker = "sys_platform == 'linux'" }, + { name = "joblib", marker = "sys_platform == 'linux'" }, + { name = "matplotlib", marker = "sys_platform == 'linux'" }, + { name = "mccd", marker = "sys_platform == 'linux'" }, + { name = "modopt", marker = "sys_platform == 'linux'" }, + { name = "mpi4py", marker = "sys_platform == 'linux'" }, + { name = "ngmix", marker = "sys_platform == 'linux'" }, + { name = "numba", marker = "sys_platform == 'linux'" }, + { name = "numpy", marker = "sys_platform == 'linux'" }, + { name = "pandas", marker = "sys_platform == 'linux'" }, + { name = "pyqt5", marker = "sys_platform == 'linux'" }, + { name = "pyqtgraph", marker = "sys_platform == 'linux'" }, + { name = "python-dateutil", marker = "sys_platform == 'linux'" }, + { name = "python-pysap", marker = "sys_platform == 'linux'" }, + { name = "reproject", marker = "sys_platform == 'linux'" }, + { name = "sf-tools", marker = "sys_platform == 'linux'" }, + { name = "skaha", marker = "sys_platform == 'linux'" }, + { name = "sqlitedict", marker = "sys_platform == 'linux'" }, + { name = "termcolor", marker = "sys_platform == 'linux'" }, + { name = "tqdm", marker = "sys_platform == 'linux'" }, + { name = "vos", marker = "sys_platform == 'linux'" }, ] [package.optional-dependencies] dev = [ - { name = "build" }, - { name = "fitsio" }, - { name = "hypothesis" }, - { name = "ipython" }, - { name = "jupyterlab" }, - { name = "myst-parser" }, - { name = "numpydoc" }, - { name = "pytest" }, - { name = "pytest-cov" }, - { name = "ruff" }, - { name = "snakemake" }, - { name = "sphinx" }, - { name = "sphinx-book-theme" }, - { name = "sphinxcontrib-bibtex" }, - { name = "twine" }, + { name = "build", marker = "sys_platform == 'linux'" }, + { name = "fitsio", marker = "sys_platform == 'linux'" }, + { name = "hypothesis", marker = "sys_platform == 'linux'" }, + { name = "ipython", marker = "sys_platform == 'linux'" }, + { name = "jupyterlab", marker = "sys_platform == 'linux'" }, + { name = "myst-parser", marker = "sys_platform == 'linux'" }, + { name = "numpydoc", marker = "sys_platform == 'linux'" }, + { name = "pytest", marker = "sys_platform == 'linux'" }, + { name = "pytest-cov", marker = "sys_platform == 'linux'" }, + { name = "ruff", marker = "sys_platform == 'linux'" }, + { name = "snakemake", marker = "sys_platform == 'linux'" }, + { name = "sphinx", marker = "sys_platform == 'linux'" }, + { name = "sphinx-book-theme", marker = "sys_platform == 'linux'" }, + { name = "sphinxcontrib-bibtex", marker = "sys_platform == 'linux'" }, + { name = "twine", marker = "sys_platform == 'linux'" }, ] doc = [ - { name = "myst-parser" }, - { name = "numpydoc" }, - { name = "sphinx" }, - { name = "sphinx-book-theme" }, - { name = "sphinxcontrib-bibtex" }, + { name = "myst-parser", marker = "sys_platform == 'linux'" }, + { name = "numpydoc", marker = "sys_platform == 'linux'" }, + { name = "sphinx", marker = "sys_platform == 'linux'" }, + { name = "sphinx-book-theme", marker = "sys_platform == 'linux'" }, + { name = "sphinxcontrib-bibtex", marker = "sys_platform == 'linux'" }, ] fitsio = [ - { name = "fitsio" }, + { name = "fitsio", marker = "sys_platform == 'linux'" }, ] jupyter = [ - { name = "ipython" }, - { name = "jupyterlab" }, - { name = "snakemake" }, + { name = "ipython", marker = "sys_platform == 'linux'" }, + { name = "jupyterlab", marker = "sys_platform == 'linux'" }, + { name = "snakemake", marker = "sys_platform == 'linux'" }, ] lint = [ - { name = "ruff" }, + { name = "ruff", marker = "sys_platform == 'linux'" }, ] release = [ - { name = "build" }, - { name = "twine" }, + { name = "build", marker = "sys_platform == 'linux'" }, + { name = "twine", marker = "sys_platform == 'linux'" }, ] test = [ - { name = "hypothesis" }, - { name = "pytest" }, - { name = "pytest-cov" }, + { name = "hypothesis", marker = "sys_platform == 'linux'" }, + { name = "pytest", marker = "sys_platform == 'linux'" }, + { name = "pytest-cov", marker = "sys_platform == 'linux'" }, ] [package.metadata] @@ -3453,6 +3455,8 @@ requires-dist = [ { name = "fitsio", marker = "extra == 'fitsio'" }, { name = "galsim", specifier = ">=2.8" }, { name = "h5py" }, + { name = "healsparse" }, + { name = "hpgeom" }, { name = "hypothesis", marker = "extra == 'test'", specifier = ">=6.155.2" }, { name = "ipython", marker = "extra == 'jupyter'", specifier = ">=9.14.1" }, { name = "joblib", specifier = ">=1.4" }, @@ -3513,13 +3517,13 @@ name = "skaha" version = "1.7.0" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "defusedxml" }, - { name = "httpx" }, - { name = "pydantic" }, - { name = "rich" }, - { name = "toml" }, - { name = "typer" }, - { name = "vos" }, + { name = "defusedxml", marker = "sys_platform == 'linux'" }, + { name = "httpx", marker = "sys_platform == 'linux'" }, + { name = "pydantic", marker = "sys_platform == 'linux'" }, + { name = "rich", marker = "sys_platform == 'linux'" }, + { name = "toml", marker = "sys_platform == 'linux'" }, + { name = "typer", marker = "sys_platform == 'linux'" }, + { name = "vos", marker = "sys_platform == 'linux'" }, ] sdist = { url = "https://files.pythonhosted.org/packages/76/62/a733508ff88200c41459f5cdb72a797eb8795c833b4e9d51d31b5efe4073/skaha-1.7.0.tar.gz", hash = "sha256:ef9d69e7a4da8653cdbde3e62f18caef137130064ccb6fabed57c7c6f8bf8ef9", size = 54414, upload-time = "2025-05-28T21:17:03.631Z" } wheels = [ @@ -3540,7 +3544,7 @@ name = "smart-open" version = "7.6.0" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "wrapt" }, + { name = "wrapt", marker = "sys_platform == 'linux'" }, ] sdist = { url = "https://files.pythonhosted.org/packages/14/33/7a00ac9b4a63afb4279b99a766f6cbe56c443526dcbf5db97b219e21fde9/smart_open-7.6.0.tar.gz", hash = "sha256:44717f46b5ff276fac03b88e5d13d1c416f064f3b7b081381b0fa8889004bd7e", size = 54548, upload-time = "2026-04-13T09:48:04.347Z" } wheels = [ @@ -3561,37 +3565,37 @@ name = "snakemake" version = "9.23.1" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "conda-inject" }, - { name = "configargparse" }, - { name = "connection-pool" }, - { name = "docutils" }, - { name = "dpath" }, - { name = "gitpython" }, - { name = "humanfriendly" }, - { name = "immutables" }, - { name = "jinja2" }, - { name = "jsonschema" }, - { name = "nbformat" }, - { name = "packaging" }, - { name = "platformdirs" }, - { name = "psutil" }, - { name = "pulp" }, - { name = "pyyaml" }, - { name = "referencing" }, - { name = "requests" }, - { name = "smart-open" }, - { name = "snakemake-interface-common" }, - { name = "snakemake-interface-executor-plugins" }, - { name = "snakemake-interface-logger-plugins" }, - { name = "snakemake-interface-report-plugins" }, - { name = "snakemake-interface-scheduler-plugins" }, - { name = "snakemake-interface-storage-plugins" }, - { name = "sqlmodel" }, - { name = "tabulate" }, - { name = "tenacity" }, - { name = "throttler" }, - { name = "wrapt" }, - { name = "yte" }, + { name = "conda-inject", marker = "sys_platform == 'linux'" }, + { name = "configargparse", marker = "sys_platform == 'linux'" }, + { name = "connection-pool", marker = "sys_platform == 'linux'" }, + { name = "docutils", marker = "sys_platform == 'linux'" }, + { name = "dpath", marker = "sys_platform == 'linux'" }, + { name = "gitpython", marker = "sys_platform == 'linux'" }, + { name = "humanfriendly", marker = "sys_platform == 'linux'" }, + { name = "immutables", marker = "sys_platform == 'linux'" }, + { name = "jinja2", marker = "sys_platform == 'linux'" }, + { name = "jsonschema", marker = "sys_platform == 'linux'" }, + { name = "nbformat", marker = "sys_platform == 'linux'" }, + { name = "packaging", marker = "sys_platform == 'linux'" }, + { name = "platformdirs", marker = "sys_platform == 'linux'" }, + { name = "psutil", marker = "sys_platform == 'linux'" }, + { name = "pulp", marker = "sys_platform == 'linux'" }, + { name = "pyyaml", marker = "sys_platform == 'linux'" }, + { name = "referencing", marker = "sys_platform == 'linux'" }, + { name = "requests", marker = "sys_platform == 'linux'" }, + { name = "smart-open", marker = "sys_platform == 'linux'" }, + { name = "snakemake-interface-common", marker = "sys_platform == 'linux'" }, + { name = "snakemake-interface-executor-plugins", marker = "sys_platform == 'linux'" }, + { name = "snakemake-interface-logger-plugins", marker = "sys_platform == 'linux'" }, + { name = "snakemake-interface-report-plugins", marker = "sys_platform == 'linux'" }, + { name = "snakemake-interface-scheduler-plugins", marker = "sys_platform == 'linux'" }, + { name = "snakemake-interface-storage-plugins", marker = "sys_platform == 'linux'" }, + { name = "sqlmodel", marker = "sys_platform == 'linux'" }, + { name = "tabulate", marker = "sys_platform == 'linux'" }, + { name = "tenacity", marker = "sys_platform == 'linux'" }, + { name = "throttler", marker = "sys_platform == 'linux'" }, + { name = "wrapt", marker = "sys_platform == 'linux'" }, + { name = "yte", marker = "sys_platform == 'linux'" }, ] sdist = { url = "https://files.pythonhosted.org/packages/9e/c2/45aa858e55edbb7dbc243ed60859f4f3d92d63ecdd67a80632aa3659fe6b/snakemake-9.23.1.tar.gz", hash = "sha256:ef8d698bfce66a6669cc29df7e344b0b367fd90956c725e5ae0a79a556e8e93f", size = 6802587, upload-time = "2026-06-18T09:42:57.653Z" } wheels = [ @@ -3603,9 +3607,9 @@ name = "snakemake-interface-common" version = "1.23.0" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "argparse-dataclass" }, - { name = "configargparse" }, - { name = "packaging" }, + { name = "argparse-dataclass", marker = "sys_platform == 'linux'" }, + { name = "configargparse", marker = "sys_platform == 'linux'" }, + { name = "packaging", marker = "sys_platform == 'linux'" }, ] sdist = { url = "https://files.pythonhosted.org/packages/89/c3/592f832f6e5d2d31f749392e48e8401b7625dec668d3d365d8d28f2b6c30/snakemake_interface_common-1.23.0.tar.gz", hash = "sha256:6ed14531a461417659364a0dd0acc51b786af4e26fc15cc5e00ff3d9fcaffacc", size = 13960, upload-time = "2026-03-08T21:54:29.251Z" } wheels = [ @@ -3617,9 +3621,9 @@ name = "snakemake-interface-executor-plugins" version = "9.4.0" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "argparse-dataclass" }, - { name = "snakemake-interface-common" }, - { name = "throttler" }, + { name = "argparse-dataclass", marker = "sys_platform == 'linux'" }, + { name = "snakemake-interface-common", marker = "sys_platform == 'linux'" }, + { name = "throttler", marker = "sys_platform == 'linux'" }, ] sdist = { url = "https://files.pythonhosted.org/packages/54/50/de06b284c45a8e94fb8e4a12d5235065e78b49b8f84329dc10fe39f4b7dd/snakemake_interface_executor_plugins-9.4.0.tar.gz", hash = "sha256:9d4138897beacbaadaedad94b63f948eaeb604b7fc78f9cf65ac57f090f2c066", size = 16549, upload-time = "2026-03-08T17:04:02.644Z" } wheels = [ @@ -3631,7 +3635,7 @@ name = "snakemake-interface-logger-plugins" version = "2.0.1" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "snakemake-interface-common" }, + { name = "snakemake-interface-common", marker = "sys_platform == 'linux'" }, ] sdist = { url = "https://files.pythonhosted.org/packages/39/1d/a489e36b4444573cc5c2c4345ed61827be5d6480ff29c489a0b43dc9749a/snakemake_interface_logger_plugins-2.0.1.tar.gz", hash = "sha256:d639cc6b3c18993d52255d8edc59ef21b17b4e4dc6ff8777f04018fbf0b430e1", size = 14601, upload-time = "2026-03-19T15:06:31.434Z" } wheels = [ @@ -3643,7 +3647,7 @@ name = "snakemake-interface-report-plugins" version = "1.3.0" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "snakemake-interface-common" }, + { name = "snakemake-interface-common", marker = "sys_platform == 'linux'" }, ] sdist = { url = "https://files.pythonhosted.org/packages/18/d6/6160ed98de665d6871dd356597dbf726688cc786e88668359ca37b7d9f54/snakemake_interface_report_plugins-1.3.0.tar.gz", hash = "sha256:fc9495298bec4e69721ab8afe6d6d88a86966fda2eeb003db56b9a88b86d5934", size = 4283, upload-time = "2025-10-31T10:52:36.55Z" } wheels = [ @@ -3655,7 +3659,7 @@ name = "snakemake-interface-scheduler-plugins" version = "2.0.2" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "snakemake-interface-common" }, + { name = "snakemake-interface-common", marker = "sys_platform == 'linux'" }, ] sdist = { url = "https://files.pythonhosted.org/packages/88/d9/d480807d2cfc2d132bc760d877d45ec8fbe620a24200ec4d2697c4a26031/snakemake_interface_scheduler_plugins-2.0.2.tar.gz", hash = "sha256:2797e8fa9019d983132c2b403f14d6fcd3c5ad4c8d8a66b984b4740a71cacc46", size = 8642, upload-time = "2025-10-20T13:58:12.988Z" } wheels = [ @@ -3667,11 +3671,11 @@ name = "snakemake-interface-storage-plugins" version = "4.4.1" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "humanfriendly" }, - { name = "snakemake-interface-common" }, - { name = "tenacity" }, - { name = "throttler" }, - { name = "wrapt" }, + { name = "humanfriendly", marker = "sys_platform == 'linux'" }, + { name = "snakemake-interface-common", marker = "sys_platform == 'linux'" }, + { name = "tenacity", marker = "sys_platform == 'linux'" }, + { name = "throttler", marker = "sys_platform == 'linux'" }, + { name = "wrapt", marker = "sys_platform == 'linux'" }, ] sdist = { url = "https://files.pythonhosted.org/packages/93/6e/f3c5b2d621fd6a6b78d8cfc01fef6b926fe2c277f5ed77c5e4deeacb94eb/snakemake_interface_storage_plugins-4.4.1.tar.gz", hash = "sha256:b2b5bf05318af36955ebf2ce76c921c0fb06904ca98fb30e1657d88b7b7b6945", size = 14924, upload-time = "2026-03-16T11:16:01.075Z" } wheels = [ @@ -3710,22 +3714,22 @@ name = "sphinx" version = "9.1.0" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "alabaster" }, - { name = "babel" }, - { name = "docutils" }, - { name = "imagesize" }, - { name = "jinja2" }, - { name = "packaging" }, - { name = "pygments" }, - { name = "requests" }, - { name = "roman-numerals" }, - { name = "snowballstemmer" }, - { name = "sphinxcontrib-applehelp" }, - { name = "sphinxcontrib-devhelp" }, - { name = "sphinxcontrib-htmlhelp" }, - { name = "sphinxcontrib-jsmath" }, - { name = "sphinxcontrib-qthelp" }, - { name = "sphinxcontrib-serializinghtml" }, + { name = "alabaster", marker = "sys_platform == 'linux'" }, + { name = "babel", marker = "sys_platform == 'linux'" }, + { name = "docutils", marker = "sys_platform == 'linux'" }, + { name = "imagesize", marker = "sys_platform == 'linux'" }, + { name = "jinja2", marker = "sys_platform == 'linux'" }, + { name = "packaging", marker = "sys_platform == 'linux'" }, + { name = "pygments", marker = "sys_platform == 'linux'" }, + { name = "requests", marker = "sys_platform == 'linux'" }, + { name = "roman-numerals", marker = "sys_platform == 'linux'" }, + { name = "snowballstemmer", marker = "sys_platform == 'linux'" }, + { name = "sphinxcontrib-applehelp", marker = "sys_platform == 'linux'" }, + { name = "sphinxcontrib-devhelp", marker = "sys_platform == 'linux'" }, + { name = "sphinxcontrib-htmlhelp", marker = "sys_platform == 'linux'" }, + { name = "sphinxcontrib-jsmath", marker = "sys_platform == 'linux'" }, + { name = "sphinxcontrib-qthelp", marker = "sys_platform == 'linux'" }, + { name = "sphinxcontrib-serializinghtml", marker = "sys_platform == 'linux'" }, ] sdist = { url = "https://files.pythonhosted.org/packages/cd/bd/f08eb0f4eed5c83f1ba2a3bd18f7745a2b1525fad70660a1c00224ec468a/sphinx-9.1.0.tar.gz", hash = "sha256:7741722357dd75f8190766926071fed3bdc211c74dd2d7d4df5404da95930ddb", size = 8718324, upload-time = "2025-12-31T15:09:27.646Z" } wheels = [ @@ -3737,8 +3741,8 @@ name = "sphinx-book-theme" version = "1.2.0" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "pydata-sphinx-theme" }, - { name = "sphinx" }, + { name = "pydata-sphinx-theme", marker = "sys_platform == 'linux'" }, + { name = "sphinx", marker = "sys_platform == 'linux'" }, ] sdist = { url = "https://files.pythonhosted.org/packages/eb/f7/154786f3cfb7692cd7acc24b6dfe4dcd1146b66f376b17df9e47125555e9/sphinx_book_theme-1.2.0.tar.gz", hash = "sha256:4a7ebfc7da4395309ac942ddfc38fbec5c5254c3be22195e99ad12586fbda9e3", size = 443962, upload-time = "2026-03-09T23:20:30.442Z" } wheels = [ @@ -3759,10 +3763,10 @@ name = "sphinxcontrib-bibtex" version = "2.7.0" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "docutils" }, - { name = "pybtex" }, - { name = "pybtex-docutils" }, - { name = "sphinx" }, + { name = "docutils", marker = "sys_platform == 'linux'" }, + { name = "pybtex", marker = "sys_platform == 'linux'" }, + { name = "pybtex-docutils", marker = "sys_platform == 'linux'" }, + { name = "sphinx", marker = "sys_platform == 'linux'" }, ] sdist = { url = "https://files.pythonhosted.org/packages/15/6a/8e0b2c2420286389e7fed78ff361ec30e2f1d58c8560af8d64df5e7b61e0/sphinxcontrib_bibtex-2.7.0.tar.gz", hash = "sha256:fee700f7aae29bb8f654c62913f00d34ac44fc0b8ca0fa67ac922ff4453addee", size = 120669, upload-time = "2026-05-06T09:29:24.935Z" } wheels = [ @@ -3819,8 +3823,8 @@ name = "sqlalchemy" version = "2.0.49" 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" }, + { name = "greenlet", marker = "(platform_machine == 'AMD64' and sys_platform == 'linux') or (platform_machine == 'WIN32' and sys_platform == 'linux') or (platform_machine == 'aarch64' and sys_platform == 'linux') or (platform_machine == 'amd64' and sys_platform == 'linux') or (platform_machine == 'ppc64le' and sys_platform == 'linux') or (platform_machine == 'win32' and sys_platform == 'linux') or (platform_machine == 'x86_64' and sys_platform == 'linux')" }, + { name = "typing-extensions", marker = "sys_platform == 'linux'" }, ] sdist = { url = "https://files.pythonhosted.org/packages/09/45/461788f35e0364a8da7bda51a1fe1b09762d0c32f12f63727998d85a873b/sqlalchemy-2.0.49.tar.gz", hash = "sha256:d15950a57a210e36dd4cec1aac22787e2a4d57ba9318233e2ef8b2daf9ff2d5f", size = 9898221, upload-time = "2026-04-03T16:38:11.704Z" } wheels = [ @@ -3858,8 +3862,8 @@ name = "sqlmodel" version = "0.0.37" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "pydantic" }, - { name = "sqlalchemy" }, + { name = "pydantic", marker = "sys_platform == 'linux'" }, + { name = "sqlalchemy", marker = "sys_platform == 'linux'" }, ] sdist = { url = "https://files.pythonhosted.org/packages/fb/26/1d2faa0fd5a765267f49751de533adac6b9ff9366c7c6e7692df4f32230f/sqlmodel-0.0.37.tar.gz", hash = "sha256:d2c19327175794faf50b1ee31cc966764f55b1dedefc046450bc5741a3d68352", size = 85527, upload-time = "2026-02-21T16:39:47.038Z" } wheels = [ @@ -3871,9 +3875,9 @@ name = "stack-data" version = "0.6.3" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "asttokens" }, - { name = "executing" }, - { name = "pure-eval" }, + { name = "asttokens", marker = "sys_platform == 'linux'" }, + { name = "executing", marker = "sys_platform == 'linux'" }, + { name = "pure-eval", marker = "sys_platform == 'linux'" }, ] sdist = { url = "https://files.pythonhosted.org/packages/28/e3/55dcc2cfbc3ca9c29519eb6884dd1415ecb53b0e934862d3559ddcb7e20b/stack_data-0.6.3.tar.gz", hash = "sha256:836a778de4fec4dcd1dcd89ed8abff8a221f58308462e1c4aa2a3cf30148f0b9", size = 44707, upload-time = "2023-09-30T13:58:05.479Z" } wheels = [ @@ -3907,7 +3911,7 @@ name = "sympy" version = "1.14.0" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "mpmath" }, + { name = "mpmath", marker = "sys_platform == 'linux'" }, ] sdist = { url = "https://files.pythonhosted.org/packages/83/d3/803453b36afefb7c2bb238361cd4ae6125a569b4db67cd9e79846ba2d68c/sympy-1.14.0.tar.gz", hash = "sha256:d3d3fe8df1e5a0b42f0e7bdf50541697dbe7d23746e894990c030e2b05e72517", size = 7793921, upload-time = "2025-04-27T18:05:01.611Z" } wheels = [ @@ -3946,8 +3950,8 @@ name = "terminado" version = "0.18.1" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "ptyprocess", marker = "os_name != 'nt'" }, - { name = "tornado" }, + { name = "ptyprocess", marker = "os_name != 'nt' and sys_platform == 'linux'" }, + { name = "tornado", marker = "sys_platform == 'linux'" }, ] sdist = { url = "https://files.pythonhosted.org/packages/8a/11/965c6fd8e5cc254f1fe142d547387da17a8ebfd75a3455f637c663fb38a0/terminado-0.18.1.tar.gz", hash = "sha256:de09f2c4b85de4765f7714688fff57d3e75bad1f909b589fde880460c753fd2e", size = 32701, upload-time = "2024-03-12T14:34:39.026Z" } wheels = [ @@ -3977,7 +3981,7 @@ name = "tifffile" version = "2026.4.11" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "numpy" }, + { name = "numpy", marker = "sys_platform == 'linux'" }, ] sdist = { url = "https://files.pythonhosted.org/packages/d7/4a/e687f5957fead200faad58dbf9c9431a2bbb118040e96f5fb8a55f7ebc50/tifffile-2026.4.11.tar.gz", hash = "sha256:17758ff0c0d4db385792a083ad3ca51fcb0f4d942642f4d8f8bc1287fdcf17bc", size = 394956, upload-time = "2026-04-12T01:57:28.793Z" } wheels = [ @@ -3989,7 +3993,7 @@ name = "tinycss2" version = "1.4.0" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "webencodings" }, + { name = "webencodings", marker = "sys_platform == 'linux'" }, ] sdist = { url = "https://files.pythonhosted.org/packages/7a/fd/7a5ee21fd08ff70d3d33a5781c255cbe779659bd03278feb98b19ee550f4/tinycss2-1.4.0.tar.gz", hash = "sha256:10c0972f6fc0fbee87c3edb76549357415e94548c1ae10ebccdea16fb404a9b7", size = 87085, upload-time = "2024-10-24T14:58:29.895Z" } wheels = [ @@ -4049,15 +4053,15 @@ name = "twine" version = "6.2.0" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "id" }, - { name = "keyring", marker = "platform_machine != 'ppc64le' and platform_machine != 's390x'" }, - { name = "packaging" }, - { name = "readme-renderer" }, - { name = "requests" }, - { name = "requests-toolbelt" }, - { name = "rfc3986" }, - { name = "rich" }, - { name = "urllib3" }, + { name = "id", marker = "sys_platform == 'linux'" }, + { name = "keyring", marker = "platform_machine != 'ppc64le' and platform_machine != 's390x' and sys_platform == 'linux'" }, + { name = "packaging", marker = "sys_platform == 'linux'" }, + { name = "readme-renderer", marker = "sys_platform == 'linux'" }, + { name = "requests", marker = "sys_platform == 'linux'" }, + { name = "requests-toolbelt", marker = "sys_platform == 'linux'" }, + { name = "rfc3986", marker = "sys_platform == 'linux'" }, + { name = "rich", marker = "sys_platform == 'linux'" }, + { name = "urllib3", marker = "sys_platform == 'linux'" }, ] sdist = { url = "https://files.pythonhosted.org/packages/e0/a8/949edebe3a82774c1ec34f637f5dd82d1cf22c25e963b7d63771083bbee5/twine-6.2.0.tar.gz", hash = "sha256:e5ed0d2fd70c9959770dce51c8f39c8945c574e18173a7b81802dab51b4b75cf", size = 172262, upload-time = "2025-09-04T15:43:17.255Z" } wheels = [ @@ -4069,10 +4073,10 @@ name = "typer" version = "0.25.0" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "annotated-doc" }, - { name = "click" }, - { name = "rich" }, - { name = "shellingham" }, + { name = "annotated-doc", marker = "sys_platform == 'linux'" }, + { name = "click", marker = "sys_platform == 'linux'" }, + { name = "rich", marker = "sys_platform == 'linux'" }, + { name = "shellingham", marker = "sys_platform == 'linux'" }, ] sdist = { url = "https://files.pythonhosted.org/packages/7b/27/ede8cec7596e0041ba7e7b80b47d132562f56ff454313a16f6084e555c9f/typer-0.25.0.tar.gz", hash = "sha256:123eaf9f19bb40fd268310e12a542c0c6b4fab9c98d9d23342a01ff95e3ce930", size = 120150, upload-time = "2026-04-26T08:46:14.767Z" } wheels = [ @@ -4093,7 +4097,7 @@ name = "typing-inspection" version = "0.4.2" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "typing-extensions" }, + { name = "typing-extensions", marker = "sys_platform == 'linux'" }, ] sdist = { url = "https://files.pythonhosted.org/packages/55/e3/70399cb7dd41c10ac53367ae42139cf4b1ca5f36bb3dc6c9d33acdb43655/typing_inspection-0.4.2.tar.gz", hash = "sha256:ba561c48a67c5958007083d386c3295464928b01faa735ab8547c5692e87f464", size = 75949, upload-time = "2025-10-01T02:14:41.687Z" } wheels = [ @@ -4132,9 +4136,9 @@ name = "vos" version = "3.6.4" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "aenum" }, - { name = "cadcutils" }, - { name = "html2text" }, + { name = "aenum", marker = "sys_platform == 'linux'" }, + { name = "cadcutils", marker = "sys_platform == 'linux'" }, + { name = "html2text", marker = "sys_platform == 'linux'" }, ] sdist = { url = "https://files.pythonhosted.org/packages/3e/6c/445bbedf2f90e71c09ff890aa8b409af5d074b1578eef383117cbcdfd09a/vos-3.6.4.tar.gz", hash = "sha256:67e4e24689ee881124b6670d7d2fc6527cc404687fc527fffc20cf5b1bd4c0bd", size = 103445, upload-time = "2025-12-12T00:20:56.398Z" } wheels = [ @@ -4221,9 +4225,9 @@ name = "yte" version = "1.9.4" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "argparse-dataclass" }, - { name = "dpath" }, - { name = "pyyaml" }, + { name = "argparse-dataclass", marker = "sys_platform == 'linux'" }, + { name = "dpath", marker = "sys_platform == 'linux'" }, + { name = "pyyaml", marker = "sys_platform == 'linux'" }, ] sdist = { url = "https://files.pythonhosted.org/packages/44/f5/7e44620e6e077bfe624b9a17c329b8e0d0159e176e1f1a93c2790428ab2c/yte-1.9.4.tar.gz", hash = "sha256:86a47e6d722cec9419a7ac88be57d0d6c4ce28f02860393b71a66f2c674069f6", size = 8101, upload-time = "2025-11-27T12:55:00.85Z" } wheels = [ @@ -4235,12 +4239,12 @@ name = "zarr" version = "3.1.6" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "donfig" }, - { name = "google-crc32c" }, - { name = "numcodecs" }, - { name = "numpy" }, - { name = "packaging" }, - { name = "typing-extensions" }, + { name = "donfig", marker = "sys_platform == 'linux'" }, + { name = "google-crc32c", marker = "sys_platform == 'linux'" }, + { name = "numcodecs", marker = "sys_platform == 'linux'" }, + { name = "numpy", marker = "sys_platform == 'linux'" }, + { name = "packaging", marker = "sys_platform == 'linux'" }, + { name = "typing-extensions", marker = "sys_platform == 'linux'" }, ] sdist = { url = "https://files.pythonhosted.org/packages/31/5a/b8a0cf39a14c770c30bd1f2d120c54000c8cd9e84e8e79f38d9a7ce58071/zarr-3.1.6.tar.gz", hash = "sha256:d95e72cbea4b90e9a70679468b8266400331756232576ae2b43400ac5108d0eb", size = 386531, upload-time = "2026-03-23T17:25:18.748Z" } wheels = [ From 2788466ab6fbbebfacc341b38f0fa4dbc45a9f57 Mon Sep 17 00:00:00 2001 From: Cail Daley Date: Thu, 16 Jul 2026 17:46:04 +0200 Subject: [PATCH 2/4] feat(mask_ext): rasterize external healsparse masks to pipeline flag images New mask_ext module (PRD in #847): reads the image WCS, evaluates the pixel grid in memory-bounded row chunks, queries the healsparse map, applies a config-driven bit->flag mapping, optionally sums the external instrument flag (matching Mask._build_final_mask semantics), and writes the standard int16 _flag.fits. Same module serves tiles and exposure CCDs; mask files and bit meanings live only in config. Example tile/exposure configs; 7 unit tests on synthetic maps (bit mapping, chunk-seam independence, RA wrap, off-map, ext-flag sum, WCS round-trip). Co-Authored-By: Claude Fable 5 Claude-Session: https://claude.ai/code/session_01CfRuCQa2UHo44yp2MZDsJX --- example/cfis/config_exp_MaExt.ini | 50 +++ example/cfis/config_tile_MaExt.ini | 51 +++ .../modules/mask_ext_package/__init__.py | 71 ++++ .../modules/mask_ext_package/mask_ext.py | 319 ++++++++++++++++++ src/shapepipe/modules/mask_ext_runner.py | 117 +++++++ tests/module/test_mask_ext.py | 230 +++++++++++++ 6 files changed, 838 insertions(+) create mode 100644 example/cfis/config_exp_MaExt.ini create mode 100644 example/cfis/config_tile_MaExt.ini create mode 100644 src/shapepipe/modules/mask_ext_package/__init__.py create mode 100644 src/shapepipe/modules/mask_ext_package/mask_ext.py create mode 100644 src/shapepipe/modules/mask_ext_runner.py create mode 100644 tests/module/test_mask_ext.py diff --git a/example/cfis/config_exp_MaExt.ini b/example/cfis/config_exp_MaExt.ini new file mode 100644 index 00000000..ecd416e1 --- /dev/null +++ b/example/cfis/config_exp_MaExt.ini @@ -0,0 +1,50 @@ +## ShapePipe configuration file for exposure-CCD external-mask (healsparse) +## rasterization. Reprojects the unified UNIONS healsparse mask through each +## single-exposure single-CCD WCS and sums in the instrument flag file, +## producing the pipeline_flag.fits artifact consumed downstream. + +[DEFAULT] +VERBOSE = True +RUN_NAME = run_sp_exp_MaExt +RUN_DATETIME = False + +[EXECUTION] +MODULE = mask_ext_runner +MODE = SMP + +[FILE] +LOG_NAME = log_sp_exp +RUN_LOG_NAME = log_run_sp +INPUT_DIR = $SP_RUN/output +OUTPUT_DIR = $SP_RUN/output + +[JOB] +SMP_BATCH_SIZE = 1 +TIMEOUT = 96:00:00 + +[MASK_EXT_RUNNER] + +# Parent module: single-exposure single-CCD images and instrument flags +INPUT_DIR = last:split_exp_runner + +# Update numbering convention, accounting for HDU number of +# single-exposure single-HDU files +NUMBERING_SCHEME = -0000000-0 + +# Path of the external healsparse mask file (band-agnostic; r-band for shear) +MASK_PATH = $SP_CONFIG/mask_r.hsp + +# Healsparse bit value -> output flag value mapping +BIT_FLAG_MAP = 64:1 + +# Flag value for pixels outside the healsparse footprint (0 = unflagged) +OFF_MAP_FLAG = 0 + +# External instrument flag file: summed into the rasterized mask +USE_EXT_FLAG = True + +# HDU of the external instrument flag FITS file (optional, default 0) +HDU = 0 + +# File name prefix for the output flag files +PREFIX = pipeline diff --git a/example/cfis/config_tile_MaExt.ini b/example/cfis/config_tile_MaExt.ini new file mode 100644 index 00000000..410a6890 --- /dev/null +++ b/example/cfis/config_tile_MaExt.ini @@ -0,0 +1,51 @@ +## ShapePipe configuration file for tile external-mask (healsparse) rasterization +## Rasterizes the unified UNIONS healsparse mask onto each tile pixel grid, +## producing the pipeline_flag.fits artifact consumed downstream. + +[DEFAULT] +VERBOSE = True +RUN_NAME = run_sp_tile_MaExt +RUN_DATETIME = False + +[EXECUTION] +MODULE = mask_ext_runner +MODE = SMP + +[FILE] +LOG_NAME = log_sp_exp +RUN_LOG_NAME = log_run_sp +INPUT_DIR = $SP_RUN/output +OUTPUT_DIR = $SP_RUN/output + +[JOB] +SMP_BATCH_SIZE = 1 +TIMEOUT = 96:00:00 + +[MASK_EXT_RUNNER] + +# Input directory, tile image +INPUT_DIR = run_sp_tile_Git:get_images_runner, last:uncompress_fits_runner + +# NUMBERING_SCHEME (optional) string with numbering pattern for input files +NUMBERING_SCHEME = -000-000 + +# Input file pattern(s): only the tile image is needed (WCS + pixel grid) +FILE_PATTERN = CFIS_image + +# FILE_EXT (optional) list of string extensions to identify input files +FILE_EXT = .fits + +# Path of the external healsparse mask file (band-agnostic; r-band for shear) +MASK_PATH = $SP_CONFIG/mask_r.hsp + +# Healsparse bit value -> output flag value mapping +BIT_FLAG_MAP = 64:1 + +# Flag value for pixels outside the healsparse footprint (0 = unflagged) +OFF_MAP_FLAG = 0 + +# No external instrument flag for tiles +USE_EXT_FLAG = False + +# File name prefix for the output flag files +PREFIX = pipeline diff --git a/src/shapepipe/modules/mask_ext_package/__init__.py b/src/shapepipe/modules/mask_ext_package/__init__.py new file mode 100644 index 00000000..4e212398 --- /dev/null +++ b/src/shapepipe/modules/mask_ext_package/__init__.py @@ -0,0 +1,71 @@ +"""MASK EXT MODULE. + +This package contains the module for ``mask_ext``. + +:Author: Cail Daley + +:Parent module: ``split_exp_runner`` (exposures) or ``get_images_runner`` / + ``uncompress_fits_runner`` (tiles), or None + +:Input: Single image (tile or single-exposure single-CCD) and, optionally, an + external instrument flag file + +:Output: Per-image pixel flag file + +Description +=========== + +This module produces the ShapePipe per-image pixel flag file +``_flag.fits`` by rasterizing an **external healsparse mask** onto +the image pixel grid, rather than generating masks internally (the job of the +``mask`` module). It is the ShapePipe consumer of the unified UNIONS healsparse +mask products (PhotoPipe footprint + bright stars, MaxiMask, manual galaxy +masks), merged and stored as ``healsparse.HealSparseMap`` files. + +For each image the module: + +1. Reads the image header into an ``astropy.wcs.WCS``. +2. Evaluates the pixel grid to (RA, Dec) in row chunks (bounded memory). +3. Queries ``HealSparseMap.get_values_pos`` at every pixel centre. +4. Maps healsparse bit values to ShapePipe flag values through the + config-driven ``BIT_FLAG_MAP``, producing an ``int16`` flag image. +5. Optionally sums in an external instrument flag image (``USE_EXT_FLAG``), + matching the combination semantics of the ``mask`` module. +6. Writes ``_flag.fits`` carrying the image WCS in its header. + +Everything downstream (SExtractor ``IMAFLAGS_ISO``, setools star selection, +vignetmaker, ngmix) consumes this artifact unchanged; the module is a drop-in +replacement for ``mask`` at the flag-image contract. + +The same module serves tiles and exposure CCDs: only the input image (hence +WCS) differs. The healsparse file, its bit meanings, and all flag values live +**only in config** — the mask products evolve and are swapped at zero code cost. + +Module-specific config file entries +=================================== + +MASK_PATH : str + Path to the healsparse mask file (``.hsp``/``.fits``); band-agnostic +BIT_FLAG_MAP : str + Mapping from healsparse pixel bit value to output flag value, formatted as + ``":, :, ..."`` (e.g. ``"64:1, 2048:2"``). A pixel + carrying several bits receives the bitwise-OR of the mapped flag values. +OFF_MAP_FLAG : int, optional + Flag value assigned to pixels that fall outside the healsparse map + footprint (sentinel pixels); default is ``0``. Off-footprint pixels are + usually unobserved, so a non-zero value flags them. +USE_EXT_FLAG : bool, optional + If ``True``, sum an external instrument flag file (given as the second + input) into the rasterized mask; default is ``False``. Needed for + exposures, where saturation / bleeding / bad columns arrive with the data. +HDU : int, optional + HDU of the external instrument flag FITS file; default is ``0`` +PREFIX : str, optional + Prefix prepended to the output file name base ``flag``; default is ``""`` +CHUNK_SIZE : int, optional + Number of image rows evaluated per chunk; default is chosen from the image + size to bound memory (``1e8`` px for tiles, ``1e7`` px for exposure CCDs) + +""" + +__all__ = ["mask_ext"] diff --git a/src/shapepipe/modules/mask_ext_package/mask_ext.py b/src/shapepipe/modules/mask_ext_package/mask_ext.py new file mode 100644 index 00000000..4edc2a12 --- /dev/null +++ b/src/shapepipe/modules/mask_ext_package/mask_ext.py @@ -0,0 +1,319 @@ +"""MASK EXT. + +This module contains a class to rasterize an external healsparse mask onto an +image pixel grid, producing the ShapePipe per-image pixel flag file. + +:Author: Cail Daley + +""" + +import re + +import numpy as np +from astropy import wcs + +from shapepipe.pipeline import file_io + +# Per-chunk pixel budget: chunk the image in row bands so that no more than +# this many pixel coordinates are held / queried at once. A tile is ~1e8 px and +# an exposure CCD ~1e7 px; this bound keeps peak memory to a single band. +DEFAULT_PIXEL_BUDGET = 10_000_000 + + +class MaskExt(object): + """Mask Ext. + + Rasterize an external healsparse mask onto an image pixel grid and write + the resulting ShapePipe flag file. + + Parameters + ---------- + image_path : str + Path to the image whose pixel grid and WCS define the output + mask_path : str + Path to the external healsparse mask file + bit_flag_map : dict + Mapping from healsparse pixel bit value (int) to output flag value + (int); a pixel carrying several bits gets the bitwise-OR of the mapped + flags + image_num : str + File number string, inserted into the output file name + output_dir : str + Path to the output directory + w_log : logging.Logger + Log file + off_map_flag : int, optional + Flag value for pixels outside the healsparse footprint (sentinel + pixels); default is ``0`` + path_external_flag : str, optional + Path to an external instrument flag file to sum into the mask; default + is ``None`` (not used) + image_prefix : str, optional + Prefix prepended to the output file name base ``flag``; specify + ``'none'`` or ``''`` for no prefix, default is ``''`` + outname_base : str, optional + Output file name base, default is ``flag`` + chunk_size : int, optional + Number of image rows evaluated per chunk; default is derived from the + image width and :data:`DEFAULT_PIXEL_BUDGET` + hdu : int, optional + HDU of the external instrument flag FITS file; default is ``0`` + + """ + + def __init__( + self, + image_path, + mask_path, + bit_flag_map, + image_num, + output_dir, + w_log, + off_map_flag=0, + path_external_flag=None, + image_prefix="", + outname_base="flag", + chunk_size=None, + hdu=0, + ): + self._image_path = image_path + self._mask_path = mask_path + self._bit_flag_map = bit_flag_map + self._img_number = image_num + self._output_dir = output_dir + self._w_log = w_log + self._off_map_flag = int(off_map_flag) + self._path_external_flag = path_external_flag + + if (image_prefix.lower() != "none") and (image_prefix != ""): + self._img_prefix = f"{image_prefix}_" + else: + self._img_prefix = "" + + self._outname_base = outname_base + self._chunk_size = chunk_size + self._hdu = hdu + + self._set_image_coordinates() + + @staticmethod + def parse_bit_flag_map(map_string): + """Parse Bit Flag Map. + + Parse the ``BIT_FLAG_MAP`` config string into a dictionary. + + Parameters + ---------- + map_string : str + Mapping formatted as ``":, :, ..."``, e.g. + ``"64:1, 2048:2"`` + + Returns + ------- + dict + Mapping from healsparse bit value (int) to output flag value (int) + + Raises + ------ + ValueError + If an entry is not of the form ``:`` + + """ + bit_flag_map = {} + for entry in map_string.split(","): + entry = entry.strip() + if not entry: + continue + if not re.fullmatch(r"\d+\s*:\s*\d+", entry): + raise ValueError( + f"Invalid BIT_FLAG_MAP entry '{entry}'; expected " + + "':'" + ) + bit, flag = (int(part) for part in entry.split(":")) + bit_flag_map[bit] = flag + if not bit_flag_map: + raise ValueError("BIT_FLAG_MAP is empty") + return bit_flag_map + + def _set_image_coordinates(self): + """Set Image Coordinates. + + Read the image header into a WCS and record the image shape, mirroring + ``Mask._set_image_coordinates``. + + """ + img = file_io.FITSCatalogue(self._image_path, hdu_no=0) + img.open() + self._header = img.get_header() + # get_data().shape is (n_y, n_x) + self._img_shape = img.get_data().shape + img.close() + del img + + self._wcs = wcs.WCS(self._header) + + def _default_chunk_size(self): + """Default Chunk Size. + + Rows per chunk such that one band holds at most + :data:`DEFAULT_PIXEL_BUDGET` pixels. + + Returns + ------- + int + Number of rows per chunk (at least 1) + + """ + n_x = self._img_shape[1] + return max(1, DEFAULT_PIXEL_BUDGET // n_x) + + def _map_bits_to_flags(self, bit_values, off_map): + """Map Bits to Flags. + + Translate healsparse bit values to output flag values through the + bit→flag mapping, OR-combining every matching bit, and assign the + off-map flag to sentinel pixels. + + Parameters + ---------- + bit_values : numpy.ndarray + Healsparse values queried at the pixel centres + off_map : numpy.ndarray + Boolean mask, ``True`` where the pixel lies outside the footprint + + Returns + ------- + numpy.ndarray + Output flag values (``int16``), same shape as ``bit_values`` + + """ + flags = np.zeros(bit_values.shape, dtype=np.int16) + for bit, flag in self._bit_flag_map.items(): + flags[(bit_values & bit) != 0] |= np.int16(flag) + if self._off_map_flag != 0: + flags[off_map] = np.int16(self._off_map_flag) + return flags + + def rasterize(self): + """Rasterize. + + Evaluate the pixel grid to (RA, Dec) in row chunks, query the + healsparse mask, and build the ``int16`` flag image. + + Returns + ------- + numpy.ndarray + The rasterized flag image, shape ``(n_y, n_x)``, dtype ``int16`` + + """ + # Lazy import: healsparse is an optional heavy dependency, imported at + # use rather than module load. + import healsparse + + hmap = healsparse.HealSparseMap.read(self._mask_path) + sentinel = hmap.sentinel + + n_y, n_x = self._img_shape + chunk_size = self._chunk_size or self._default_chunk_size() + + flag_image = np.zeros((n_y, n_x), dtype=np.int16) + # Column indices are shared across every row band. + x = np.arange(n_x) + + for y0 in range(0, n_y, chunk_size): + y1 = min(y0 + chunk_size, n_y) + yy, xx = np.meshgrid(np.arange(y0, y1), x, indexing="ij") + # WCS uses 0-based pixel coordinates here (origin=0). + ra, dec = self._wcs.all_pix2world(xx.ravel(), yy.ravel(), 0) + # Normalize RA into [0, 360) so the wrap at 0/360 is handled; + # healsparse expects lon in that range with lonlat=True. + ra = np.mod(ra, 360.0) + + bit_values = hmap.get_values_pos(ra, dec, lonlat=True) + off_map = bit_values == sentinel + + band = self._map_bits_to_flags(bit_values, off_map) + flag_image[y0:y1, :] = band.reshape(y1 - y0, n_x) + + return flag_image + + def _combine_external_flag(self, flag_image): + """Combine External Flag. + + Sum an external instrument flag image into the rasterized mask, + matching ``Mask._build_final_mask`` semantics (element-wise sum of the + two integer flag images). + + Parameters + ---------- + flag_image : numpy.ndarray + The rasterized flag image + + Returns + ------- + numpy.ndarray + The combined flag image (``int16``) + + """ + external_flag = file_io.FITSCatalogue( + self._path_external_flag, + hdu_no=self._hdu, + ) + external_flag.open() + ext_flag = external_flag.get_data()[:, :] + external_flag.close() + + return (flag_image + ext_flag).astype(np.int16, copy=False) + + def _output_path(self): + """Output Path. + + Full path of the output flag file, matching the ``mask`` module naming + (``_flag.fits``). + + Returns + ------- + str + Output file path + + """ + name = ( + f"{self._img_prefix}{self._outname_base}" + + f"{self._img_number}.fits" + ) + return f"{self._output_dir}/{name}" + + def make_mask(self): + """Make Mask. + + Rasterize the healsparse mask, optionally combine the external + instrument flag, and write the flag file carrying the image WCS. + + Returns + ------- + str + Path to the written flag file + + """ + flag_image = self.rasterize() + + if self._path_external_flag is not None: + flag_image = self._combine_external_flag(flag_image) + + output_path = self._output_path() + out = file_io.FITSCatalogue( + output_path, + open_mode=file_io.BaseCatalogue.OpenMode.ReadWrite, + hdu_no=0, + ) + out.save_as_fits( + data=flag_image, + image=True, + image_header=self._wcs.to_header(), + ) + + self._w_log.info( + f"Wrote healsparse-derived flag file {output_path}" + ) + + return output_path diff --git a/src/shapepipe/modules/mask_ext_runner.py b/src/shapepipe/modules/mask_ext_runner.py new file mode 100644 index 00000000..a43265d1 --- /dev/null +++ b/src/shapepipe/modules/mask_ext_runner.py @@ -0,0 +1,117 @@ +"""MASK EXT RUNNER. + +Module runner for ``mask_ext``. + +:Author: Cail Daley + +""" + +from shapepipe.modules.mask_ext_package.mask_ext import MaskExt +from shapepipe.modules.module_decorator import module_runner + + +@module_runner( + version="1.0", + file_pattern=["image", "flag"], + file_ext=[".fits", ".fits"], + depends=["numpy", "astropy", "healsparse"], + numbering_scheme="_0", +) +def mask_ext_runner( + input_file_list, + run_dirs, + file_number_string, + config, + module_config_sec, + w_log, +): + """Define The Mask Ext Runner. + + Rasterize an external healsparse mask onto the input image pixel grid and + write the ShapePipe flag file. + + Notes + ----- + Only the image is strictly required: it supplies the pixel grid and WCS + onto which the healsparse mask is rasterized. Unlike the ``mask`` module, + no weight file is used — the healsparse mask already encodes the footprint, + and missing-data handling is not this module's concern. A second input, an + external instrument flag file, is consumed only when ``USE_EXT_FLAG`` is + ``True`` (needed for exposures, where saturation / bleeding / bad columns + arrive with the data). + + """ + n_inputs = len(input_file_list) + use_ext_flag = config.getboolean(module_config_sec, "USE_EXT_FLAG") if ( + config.has_option(module_config_sec, "USE_EXT_FLAG") + ) else False + + if use_ext_flag: + if n_inputs != 2: + raise ValueError( + f"Found {n_inputs} inputs but USE_EXT_FLAG is True, which " + + 'expects "image" and "flag" in the MASK_EXT_RUNNER section ' + + "of the config file." + ) + image_path = input_file_list[0] + ext_flag_name = input_file_list[1] + else: + if n_inputs != 1: + raise ValueError( + f"Found {n_inputs} inputs but USE_EXT_FLAG is False, which " + + 'expects only "image" in the MASK_EXT_RUNNER section of the ' + + "config file." + ) + image_path = input_file_list[0] + ext_flag_name = None + + # Path to the healsparse mask file + mask_path = config.getexpanded(module_config_sec, "MASK_PATH") + + # Bit -> flag mapping + bit_flag_map = MaskExt.parse_bit_flag_map( + config.get(module_config_sec, "BIT_FLAG_MAP") + ) + + # Flag value for pixels outside the healsparse footprint + if config.has_option(module_config_sec, "OFF_MAP_FLAG"): + off_map_flag = config.getint(module_config_sec, "OFF_MAP_FLAG") + else: + off_map_flag = 0 + + # HDU of the external instrument flag file + if config.has_option(module_config_sec, "HDU"): + hdu = config.getint(module_config_sec, "HDU") + else: + hdu = 0 + + # Output file name prefix + if config.has_option(module_config_sec, "PREFIX"): + prefix = config.get(module_config_sec, "PREFIX") + else: + prefix = "" + + # Rows per chunk (optional; default derived from image size) + if config.has_option(module_config_sec, "CHUNK_SIZE"): + chunk_size = config.getint(module_config_sec, "CHUNK_SIZE") + else: + chunk_size = None + + mask_inst = MaskExt( + image_path, + mask_path, + bit_flag_map, + file_number_string, + run_dirs["output"], + w_log, + off_map_flag=off_map_flag, + path_external_flag=ext_flag_name, + image_prefix=prefix.replace(" ", ""), + outname_base="flag", + chunk_size=chunk_size, + hdu=hdu, + ) + + mask_inst.make_mask() + + return None, None diff --git a/tests/module/test_mask_ext.py b/tests/module/test_mask_ext.py new file mode 100644 index 00000000..f1843f2c --- /dev/null +++ b/tests/module/test_mask_ext.py @@ -0,0 +1,230 @@ +"""UNIT TESTS FOR MODULE PACKAGE: MASK_EXT. + +Drives ``MaskExt`` against a synthetic healsparse map and a synthetic TAN WCS +to lock in the rasterization contract of ``mask_ext_runner``: the config-driven +bit->flag mapping (with bitwise-OR of multiple bits), chunk-seam independence, +RA wrap across 0/360, off-footprint (sentinel) handling, external-flag summing, +``int16`` output dtype, and WCS round-trip in the written FITS. + +The synthetic map is a high-resolution healsparse map covering only a tiny +patch on the sky; the synthetic WCS points an image at that patch so a subset +of pixels land on masked healpix cells and the rest fall off the footprint. +""" + +import numpy as np +import numpy.testing as npt +import pytest +from astropy.io import fits +from astropy.wcs import WCS + +healsparse = pytest.importorskip("healsparse") +hpgeom = pytest.importorskip("hpgeom") + +from shapepipe.modules.mask_ext_package.mask_ext import MaskExt + + +class _NullLogger: + def info(self, *_args, **_kwargs): + pass + + +# Sky patch the synthetic image and mask share. +CRVAL1 = 150.0 +CRVAL2 = 2.3 +NSIDE_SPARSE = 131072 # ~1.6 arcsec, matching the real UNIONS masks +NSIDE_COVERAGE = 32 +PIXSCALE_DEG = 0.187 / 3600.0 # UNIONS ~0.187"/px + + +def _make_wcs(naxis1, naxis2, crval1=CRVAL1, crval2=CRVAL2): + """Synthetic TAN WCS header centred on the shared patch.""" + w = WCS(naxis=2) + w.wcs.ctype = ["RA---TAN", "DEC--TAN"] + w.wcs.crval = [crval1, crval2] + w.wcs.crpix = [naxis1 / 2 + 0.5, naxis2 / 2 + 0.5] + w.wcs.cd = [[-PIXSCALE_DEG, 0.0], [0.0, PIXSCALE_DEG]] + return w + + +def _write_image(path, wcs_obj, naxis1, naxis2): + """Write a zero-valued image carrying the given WCS (defines pixel grid).""" + data = np.zeros((naxis2, naxis1), dtype=np.float32) + hdu = fits.PrimaryHDU(data) + # NAXIS* are set from the data shape; merge only the WCS keywords. + hdu.header.update(wcs_obj.to_header()) + hdu.writeto(path, overwrite=True) + + +def _make_map(masked_ra, masked_dec, bits, sentinel=0): + """Healsparse int32 map with the given (ra, dec) cells set to ``bits``.""" + hmap = healsparse.HealSparseMap.make_empty( + NSIDE_COVERAGE, NSIDE_SPARSE, dtype=np.int32, sentinel=sentinel + ) + pix = hpgeom.angle_to_pixel(NSIDE_SPARSE, masked_ra, masked_dec) + bits = np.asarray(bits, dtype=np.int32) + # Several fine image pixels can share one healpix cell; keep the first bit + # value per unique cell (replace requires unique pixels). + pix, first = np.unique(pix, return_index=True) + hmap[pix] = bits[first] + return hmap + + +def _run(tmp_path, image_wcs, naxis1, naxis2, hmap, bit_flag_map, + off_map_flag=0, chunk_size=None, path_external_flag=None): + """Instantiate MaskExt on written synthetic inputs and rasterize/write.""" + image_path = str(tmp_path / "image.fits") + mask_path = str(tmp_path / "mask.hsp") + _write_image(image_path, image_wcs, naxis1, naxis2) + hmap.write(mask_path, clobber=True) + + inst = MaskExt( + image_path, + mask_path, + bit_flag_map, + image_num="-000-000", + output_dir=str(tmp_path), + w_log=_NullLogger(), + off_map_flag=off_map_flag, + path_external_flag=path_external_flag, + image_prefix="pipeline", + chunk_size=chunk_size, + ) + return inst + + +def test_parse_bit_flag_map(): + """String config parses into an int->int dict; malformed entries raise.""" + assert MaskExt.parse_bit_flag_map("64:1, 2048:2") == {64: 1, 2048: 2} + assert MaskExt.parse_bit_flag_map(" 64 : 1 ") == {64: 1} + with pytest.raises(ValueError): + MaskExt.parse_bit_flag_map("64") + with pytest.raises(ValueError): + MaskExt.parse_bit_flag_map("") + + +def test_bit_flag_mapping_and_off_map(tmp_path): + """Masked cells map their bit; unmasked (off-footprint) get off_map_flag. + + The image centre pixel lands on a cell carrying bit 64 -> flag 1; the map + covers only that centre cell, so every other pixel is off-footprint. + """ + naxis1 = naxis2 = 16 + w = _make_wcs(naxis1, naxis2) + # RA/Dec at the central pixel (0-based grid, origin=0). + cx, cy = naxis1 // 2, naxis2 // 2 + ra_c, dec_c = w.all_pix2world(cx, cy, 0) + hmap = _make_map([float(ra_c)], [float(dec_c)], [64]) + + inst = _run(tmp_path, w, naxis1, naxis2, hmap, {64: 1}, off_map_flag=8) + flags = inst.rasterize() + + assert flags.dtype == np.int16 + assert flags.shape == (naxis2, naxis1) + # The centre cell is flagged 1; the rest of the image is off the footprint. + n_flagged_1 = np.sum(flags == 1) + assert n_flagged_1 >= 1 + assert np.all(flags[flags != 1] == 8) + assert np.sum(flags == 8) == flags.size - n_flagged_1 + + +def test_multi_bit_or(tmp_path): + """A cell carrying two bits gets the bitwise-OR of the mapped flags.""" + naxis1 = naxis2 = 8 + w = _make_wcs(naxis1, naxis2) + cx, cy = naxis1 // 2, naxis2 // 2 + ra_c, dec_c = w.all_pix2world(cx, cy, 0) + # bit values 64 and 2048 set together on the centre cell. + hmap = _make_map([float(ra_c)], [float(dec_c)], [64 | 2048]) + + inst = _run(tmp_path, w, naxis1, naxis2, hmap, {64: 1, 2048: 2}) + flags = inst.rasterize() + # 1 | 2 == 3 on the masked cell. + assert 3 in np.unique(flags) + assert np.all(np.isin(np.unique(flags), [0, 3])) + + +def test_chunk_seam_independence(tmp_path): + """Result is independent of chunk size (no seam artifacts).""" + naxis1 = naxis2 = 40 + w = _make_wcs(naxis1, naxis2) + # Mask a band of cells spanning several image rows. + ys = np.arange(0, naxis2) + xs = np.full_like(ys, naxis1 // 2) + ra, dec = w.all_pix2world(xs, ys, 0) + hmap = _make_map(ra.astype(float), dec.astype(float), [64] * len(ys)) + + inst_full = _run(tmp_path, w, naxis1, naxis2, hmap, {64: 1}) + full = inst_full.rasterize() + + for cs in (1, 3, 7, 40): + inst = _run(tmp_path, w, naxis1, naxis2, hmap, {64: 1}, chunk_size=cs) + npt.assert_array_equal(inst.rasterize(), full) + # Sanity: some pixels actually got flagged. + assert np.any(full == 1) + + +def test_ra_wrap(tmp_path): + """RA-wrap near 0/360: an image centred on RA~0 rasterizes correctly.""" + naxis1 = naxis2 = 16 + w = _make_wcs(naxis1, naxis2, crval1=0.0, crval2=2.3) + cx, cy = naxis1 // 2, naxis2 // 2 + ra_c, dec_c = w.all_pix2world(cx, cy, 0) + # Straddling pixels produce RA both just below 360 and just above 0; the + # map cell is queried by its wrapped-into-[0,360) coordinate. + hmap = _make_map([float(np.mod(ra_c, 360.0))], [float(dec_c)], [64]) + + inst = _run(tmp_path, w, naxis1, naxis2, hmap, {64: 1}) + flags = inst.rasterize() + # No crash, correct dtype, and the centre is flagged despite the wrap. + assert flags.dtype == np.int16 + assert np.any(flags == 1) + + +def test_external_flag_summing(tmp_path): + """External instrument flag image is summed into the rasterized mask.""" + naxis1 = naxis2 = 8 + w = _make_wcs(naxis1, naxis2) + cx, cy = naxis1 // 2, naxis2 // 2 + ra_c, dec_c = w.all_pix2world(cx, cy, 0) + hmap = _make_map([float(ra_c)], [float(dec_c)], [64]) + + # External flag: a constant field of 16 (e.g. a saturation bit). + ext_path = str(tmp_path / "ext_flag.fits") + ext_data = np.full((naxis2, naxis1), 16, dtype=np.int16) + fits.PrimaryHDU(ext_data).writeto(ext_path, overwrite=True) + + inst = _run( + tmp_path, w, naxis1, naxis2, hmap, {64: 1}, + path_external_flag=ext_path, + ) + out_path = inst.make_mask() + + with fits.open(out_path) as hdul: + written = hdul[0].data + + # FITS stores big-endian; still a 2-byte signed int (int16). + assert written.dtype.kind == "i" and written.dtype.itemsize == 2 + # Every pixel gets +16 from the external flag; the centre cell also +1. + assert np.all(written >= 16) + assert 17 in np.unique(written) + + +def test_write_wcs_roundtrip(tmp_path): + """Written FITS carries the image WCS; pix2world round-trips.""" + naxis1 = naxis2 = 12 + w = _make_wcs(naxis1, naxis2) + cx, cy = naxis1 // 2, naxis2 // 2 + ra_c, dec_c = w.all_pix2world(cx, cy, 0) + hmap = _make_map([float(ra_c)], [float(dec_c)], [64]) + + inst = _run(tmp_path, w, naxis1, naxis2, hmap, {64: 1}) + out_path = inst.make_mask() + + with fits.open(out_path) as hdul: + assert hdul[0].data.dtype.kind == "i" + assert hdul[0].data.dtype.itemsize == 2 + w_out = WCS(hdul[0].header) + + ra_in, dec_in = w.all_pix2world(cx, cy, 0) + ra_out, dec_out = w_out.all_pix2world(cx, cy, 0) + npt.assert_allclose([ra_in, dec_in], [ra_out, dec_out], rtol=0, atol=1e-9) From 04003d2bb168f4fdd11632f669315948a4c28245 Mon Sep 17 00:00:00 2001 From: Cail Daley Date: Thu, 16 Jul 2026 17:46:06 +0200 Subject: [PATCH 3/4] feat(make_cat): per-band MASK_ columns from external healsparse maps MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Optional MASK_EXT_PATHS (band:path pairs, env-expanded) in the make_cat section: each band's healsparse map is queried at object world positions (XWIN_WORLD/YWIN_WORLD) and added as a MASK_ column — the ShapePipe end of UNIONS-WL/spherex#38. Strict no-op when unset; off-map objects carry the map sentinel (-1 for integer maps). 3 unit tests. Co-Authored-By: Claude Fable 5 Claude-Session: https://claude.ai/code/session_01CfRuCQa2UHo44yp2MZDsJX --- .../modules/make_cat_package/make_cat.py | 62 +++++++++ src/shapepipe/modules/make_cat_runner.py | 10 ++ tests/module/test_make_cat_mask_ext.py | 129 ++++++++++++++++++ 3 files changed, 201 insertions(+) create mode 100644 tests/module/test_make_cat_mask_ext.py diff --git a/src/shapepipe/modules/make_cat_package/make_cat.py b/src/shapepipe/modules/make_cat_package/make_cat.py index 32855bdd..d9fed353 100644 --- a/src/shapepipe/modules/make_cat_package/make_cat.py +++ b/src/shapepipe/modules/make_cat_package/make_cat.py @@ -209,6 +209,68 @@ def save_sm_data( return n_obj +def parse_mask_ext_paths(paths_str): + """Parse Mask Ext Paths. + + Parse the ``MASK_EXT_PATHS`` config value into a ``band -> path`` mapping. + + Parameters + ---------- + paths_str : str + Comma-separated ``band:path`` pairs, e.g. + ``u:/path/mask_u.hsp, g:/path/mask_g.hsp`` + + Returns + ------- + dict + Mapping from band name to healsparse map path + + """ + band_paths = {} + for pair in paths_str.split(","): + band, path = pair.split(":", 1) + band_paths[band.strip()] = path.strip() + + return band_paths + + +def save_mask_ext_data(final_cat_file, band_paths, w_log): + """Save External Mask Data. + + Query per-band external healsparse masks at each object's world position + and write one ``MASK_`` column per band into the final catalogue. + Object positions are read from the SExtractor windowed world coordinates + (``XWIN_WORLD`` = RA, ``YWIN_WORLD`` = Dec, both in degrees) carried in the + ``RESULTS`` extension. Objects falling outside a map's coverage receive + that map's sentinel value (``healsparse.HealSparseMap.get_values_pos`` + returns the map's sentinel — ``-1`` for integer maps — verbatim), which is + the documented off-map flag. + + Parameters + ---------- + final_cat_file : file_io.FITSCatalogue + Final catalogue + band_paths : dict + Mapping from band name to healsparse map path + w_log : logging.Logger + Logging instance + + """ + import healsparse + + final_cat_file.open() + ra = np.copy(final_cat_file.get_data()["XWIN_WORLD"]) + dec = np.copy(final_cat_file.get_data()["YWIN_WORLD"]) + + for band, path in band_paths.items(): + w_log.info(f"Query external mask for band {band}: {path}") + mask_map = healsparse.HealSparseMap.read(path) + values = mask_map.get_values_pos(ra, dec, lonlat=True) + final_cat_file.add_col(f"MASK_{band}", np.asarray(values)) + + final_cat_file.close() + + class SaveCatalogue: """Save Catalogue. diff --git a/src/shapepipe/modules/make_cat_runner.py b/src/shapepipe/modules/make_cat_runner.py index 307dc2ff..17634175 100644 --- a/src/shapepipe/modules/make_cat_runner.py +++ b/src/shapepipe/modules/make_cat_runner.py @@ -137,4 +137,14 @@ def make_cat_runner( if save_psf: err_msg = sc_inst.process("psf", galaxy_psf_path) + # Optional per-band external healsparse mask lookup (UNIONS-WL/spherex#38): + # add one MASK_ column per band, queried at each object's world + # position. Absent config is a strict no-op. + if config.has_option(module_config_sec, "MASK_EXT_PATHS"): + band_paths = make_cat.parse_mask_ext_paths( + config.getexpanded(module_config_sec, "MASK_EXT_PATHS") + ) + w_log.info("Save external mask data") + make_cat.save_mask_ext_data(final_cat_file, band_paths, w_log) + return None, None diff --git a/tests/module/test_make_cat_mask_ext.py b/tests/module/test_make_cat_mask_ext.py new file mode 100644 index 00000000..91d0f515 --- /dev/null +++ b/tests/module/test_make_cat_mask_ext.py @@ -0,0 +1,129 @@ +"""UNIT TESTS FOR MODULE PACKAGE: MAKE_CAT external-mask columns. + +Exercises the optional per-band external healsparse mask lookup added to +``make_cat`` (PR #847 §4, the ShapePipe end of UNIONS-WL/spherex#38). A small +synthetic ``final_cat`` FITS carrying known ``XWIN_WORLD`` / ``YWIN_WORLD`` +object positions is queried against synthetic healsparse maps of known value, +locking in: (1) the ``MASK_`` column name and per-object values, (2) the +off-map sentinel (``-1`` for integer maps) written verbatim for objects outside +coverage, (3) multi-band handling, and (4) that absent config leaves the +catalogue untouched. +""" + +import numpy as np +import numpy.testing as npt +import pytest + +healsparse = pytest.importorskip("healsparse") + +from shapepipe.modules.make_cat_package import make_cat +from shapepipe.pipeline import file_io + + +class _NullLogger: + def info(self, *_args, **_kwargs): + pass + + +NSIDE_COVERAGE = 32 +NSIDE_SPARSE = 4096 + +# Object world positions (RA, Dec in degrees). The last object sits far from +# the map coverage so it exercises the off-map sentinel path. +RA = np.array([10.0, 10.1, 10.2, 200.0]) +DEC = np.array([20.0, 20.1, 20.2, -40.0]) + + +def _make_map(value, dtype=np.int16, sentinel=-1): + """Build a healsparse map covering the first three RA/Dec positions. + + All covered pixels carry ``value``; everything else reads the sentinel. + """ + smap = healsparse.HealSparseMap.make_empty( + NSIDE_COVERAGE, NSIDE_SPARSE, dtype, sentinel=sentinel + ) + smap.update_values_pos( + RA[:3], DEC[:3], np.full(3, value, dtype=dtype), lonlat=True + ) + return smap + + +def _write_final_cat(path): + """Write a synthetic final_cat FITS with a RESULTS ext of known positions.""" + data = np.empty( + len(RA), + dtype=[ + ("NUMBER", "i4"), + ("XWIN_WORLD", "f8"), + ("YWIN_WORLD", "f8"), + ], + ) + data["NUMBER"] = np.arange(len(RA)) + data["XWIN_WORLD"] = RA + data["YWIN_WORLD"] = DEC + + cat = file_io.FITSCatalogue( + str(path), + open_mode=file_io.BaseCatalogue.OpenMode.ReadWrite, + ) + cat.save_as_fits(data, ext_name="RESULTS") + return cat + + +def test_parse_mask_ext_paths(): + """band:path pairs parse into a stripped mapping, whitespace-tolerant.""" + parsed = make_cat.parse_mask_ext_paths( + "u:/a/mask_u.hsp, g:/b/mask_g.hsp,r:/c/mask_r.hsp" + ) + assert parsed == { + "u": "/a/mask_u.hsp", + "g": "/b/mask_g.hsp", + "r": "/c/mask_r.hsp", + } + + +def test_mask_ext_columns(tmp_path): + """Per-band columns carry the map value on-map and the sentinel off-map.""" + u_map = _make_map(16) + g_map = _make_map(32) + u_path = tmp_path / "mask_u.hsp" + g_path = tmp_path / "mask_g.hsp" + u_map.write(str(u_path)) + g_map.write(str(g_path)) + + cat_path = tmp_path / "final_cat-000.fits" + _write_final_cat(cat_path) + + cat = file_io.FITSCatalogue( + str(cat_path), + open_mode=file_io.BaseCatalogue.OpenMode.ReadWrite, + ) + make_cat.save_mask_ext_data( + cat, + {"u": str(u_path), "g": str(g_path)}, + _NullLogger(), + ) + + cat.open() + data = cat.get_data() + # On-map objects (first three) carry the map value; the off-map object + # (last) carries the map's -1 sentinel. + npt.assert_array_equal(data["MASK_u"], [16, 16, 16, -1]) + npt.assert_array_equal(data["MASK_g"], [32, 32, 32, -1]) + # Integer dtype preserved from the map. + assert np.issubdtype(data["MASK_u"].dtype, np.integer) + cat.close() + + +def test_mask_ext_absent_is_noop(tmp_path): + """Not calling the lookup leaves the catalogue columns unchanged.""" + cat_path = tmp_path / "final_cat-001.fits" + _write_final_cat(cat_path) + + cat = file_io.FITSCatalogue(str(cat_path)) + cat.open() + cols = set(cat.get_data().dtype.names) + cat.close() + + assert cols == {"NUMBER", "XWIN_WORLD", "YWIN_WORLD"} + assert not any(name.startswith("MASK_") for name in cols) From 6f2f708b56537ccb402b92c883a17c2cac56eac1 Mon Sep 17 00:00:00 2001 From: Cail Daley Date: Thu, 16 Jul 2026 18:32:24 +0200 Subject: [PATCH 4/4] feat(mask_ext): fail fast on boolean masks with non-1 bits The real 2025 r-band UNIONS mask (mask_r_nside131072.hsp) is a boolean healsparse map (True = masked), not an integer bit-flag map. With a boolean map, any BIT_FLAG_MAP bit other than 1 silently selects nothing (True & 64 == 0), producing an all-clean flag image. Raise instead, and document the two mask flavours in the example configs. Found by the real-data smoke: rasterizing the candide mask copy onto the CFIS.233.293 tile grid. Co-Authored-By: Claude Fable 5 Claude-Session: https://claude.ai/code/session_013btLTHCgmiiggZmxJ4hM3n --- example/cfis/config_exp_MaExt.ini | 4 +- example/cfis/config_tile_MaExt.ini | 4 +- .../modules/mask_ext_package/mask_ext.py | 14 ++++++ tests/module/test_mask_ext.py | 44 +++++++++++++++++++ 4 files changed, 64 insertions(+), 2 deletions(-) diff --git a/example/cfis/config_exp_MaExt.ini b/example/cfis/config_exp_MaExt.ini index ecd416e1..ccb527dd 100644 --- a/example/cfis/config_exp_MaExt.ini +++ b/example/cfis/config_exp_MaExt.ini @@ -34,7 +34,9 @@ NUMBERING_SCHEME = -0000000-0 # Path of the external healsparse mask file (band-agnostic; r-band for shear) MASK_PATH = $SP_CONFIG/mask_r.hsp -# Healsparse bit value -> output flag value mapping +# Healsparse bit value -> output flag value mapping. +# Integer bit-flag masks use per-band bits (e.g. 64 = r); boolean masks +# (True = masked, e.g. mask_r_nside131072.hsp) use 1:. BIT_FLAG_MAP = 64:1 # Flag value for pixels outside the healsparse footprint (0 = unflagged) diff --git a/example/cfis/config_tile_MaExt.ini b/example/cfis/config_tile_MaExt.ini index 410a6890..fce00da1 100644 --- a/example/cfis/config_tile_MaExt.ini +++ b/example/cfis/config_tile_MaExt.ini @@ -38,7 +38,9 @@ FILE_EXT = .fits # Path of the external healsparse mask file (band-agnostic; r-band for shear) MASK_PATH = $SP_CONFIG/mask_r.hsp -# Healsparse bit value -> output flag value mapping +# Healsparse bit value -> output flag value mapping. +# Integer bit-flag masks use per-band bits (e.g. 64 = r); boolean masks +# (True = masked, e.g. mask_r_nside131072.hsp) use 1:. BIT_FLAG_MAP = 64:1 # Flag value for pixels outside the healsparse footprint (0 = unflagged) diff --git a/src/shapepipe/modules/mask_ext_package/mask_ext.py b/src/shapepipe/modules/mask_ext_package/mask_ext.py index 4edc2a12..c24aaabc 100644 --- a/src/shapepipe/modules/mask_ext_package/mask_ext.py +++ b/src/shapepipe/modules/mask_ext_package/mask_ext.py @@ -213,6 +213,20 @@ def rasterize(self): hmap = healsparse.HealSparseMap.read(self._mask_path) sentinel = hmap.sentinel + # Mask products come in two flavours: integer bit-flag maps (per-band + # bits, e.g. 64 = r) and boolean maps (True = masked, e.g. the + # candide copy of the 2025 r-band mask). For a boolean map the only + # meaningful bit is 1 (True); any other bit silently selects nothing + # (``True & 64 == 0`` -> an all-clean flag image), so fail loudly. + if hmap.dtype == np.bool_: + bad_bits = [bit for bit in self._bit_flag_map if bit != 1] + if bad_bits: + raise ValueError( + f"Mask {self._mask_path} is a boolean healsparse map; " + + f"BIT_FLAG_MAP bits {bad_bits} would never match " + + "(use '1:' for boolean masks)" + ) + n_y, n_x = self._img_shape chunk_size = self._chunk_size or self._default_chunk_size() diff --git a/tests/module/test_mask_ext.py b/tests/module/test_mask_ext.py index f1843f2c..6958c9e0 100644 --- a/tests/module/test_mask_ext.py +++ b/tests/module/test_mask_ext.py @@ -228,3 +228,47 @@ def test_write_wcs_roundtrip(tmp_path): ra_in, dec_in = w.all_pix2world(cx, cy, 0) ra_out, dec_out = w_out.all_pix2world(cx, cy, 0) npt.assert_allclose([ra_in, dec_in], [ra_out, dec_out], rtol=0, atol=1e-9) + + +def _make_bool_map(masked_ra, masked_dec): + """Healsparse boolean map (True = masked) at the given (ra, dec) cells.""" + hmap = healsparse.HealSparseMap.make_empty( + NSIDE_COVERAGE, NSIDE_SPARSE, dtype=np.bool_, sentinel=False + ) + pix = np.unique(hpgeom.angle_to_pixel(NSIDE_SPARSE, masked_ra, masked_dec)) + hmap[pix] = np.ones(len(pix), dtype=np.bool_) + return hmap + + +def test_bool_map_flag_1(tmp_path): + """A boolean mask (True = masked) rasterizes through BIT_FLAG_MAP 1:1. + + This is the flavour of the real 2025 r-band UNIONS mask + (``mask_r_nside131072.hsp``): dtype bool, sentinel False, valid pixels + only where masked. + """ + naxis1 = naxis2 = 16 + w = _make_wcs(naxis1, naxis2) + cx, cy = naxis1 // 2, naxis2 // 2 + ra_c, dec_c = w.all_pix2world(cx, cy, 0) + hmap = _make_bool_map([float(ra_c)], [float(dec_c)]) + + inst = _run(tmp_path, w, naxis1, naxis2, hmap, {1: 1}) + flags = inst.rasterize() + + assert flags.dtype == np.int16 + assert np.sum(flags == 1) >= 1 + assert np.all(np.isin(np.unique(flags), [0, 1])) + + +def test_bool_map_wrong_bits_raise(tmp_path): + """Boolean mask + bits other than 1 would silently select nothing: raise.""" + naxis1 = naxis2 = 8 + w = _make_wcs(naxis1, naxis2) + cx, cy = naxis1 // 2, naxis2 // 2 + ra_c, dec_c = w.all_pix2world(cx, cy, 0) + hmap = _make_bool_map([float(ra_c)], [float(dec_c)]) + + inst = _run(tmp_path, w, naxis1, naxis2, hmap, {64: 1}) + with pytest.raises(ValueError, match="boolean healsparse map"): + inst.rasterize()