<h2>
<img alt="palom" height="60" src="palom-logo.svg">
<br>
Piecewise alignment for layers of mosaics
</h2>
Palom started as a tool for registering [whole-slide
images](https://en.wikipedia.org/wiki/Digital_pathology) of the same [FFPE
section](https://en.wikipedia.org/wiki/Histology#Sample_preparation) with
different [IHC stainings](https://en.wikipedia.org/wiki/Immunohistochemistry).
---
## Installation
Installing palom in a fresh conda environment is recommended. [Instruction for
installing miniconda](https://docs.conda.io/en/latest/miniconda.html)
### Step 1
Create a named conda environment - _palom_, in the following example, and activate the environment.
```
conda create -n palom python=3.10 pip -c conda-forge
conda activate palom
```
### Step 2
Install openslide in the conda environment.
- For MacOS, use conda-forge channel
```
conda install openslide -c conda-forge
```
- For Windows and Linux, use sdvillal channel
```
conda install openslide -c sdvillal
```
### Step 3
Install palom from pypi in the conda environment.
```
python -m pip install palom
```
---
## CLI usage
### Configuration YAML file
Palom CLI tool merges multiple SVS files into a pyramidal OME-TIFF file, with
the option to perform preset stain separation (5 modes are available - `output
mode`: `hematoxylin`, `aec`, `dab`, `grayscale`, `color`)
A user-defined configuration YAML file is required for the run. A configuration
example can be printed to the console by running
```bash
palom-svs show example
```
```yaml
input dir: Y:\user\me\projects\data\mihc
output full path: Y:\user\me\projects\analysis\mihc\2021\skin-case-356.ome.tif
reference image:
filename: 20210111/skin_case_356_HEM_C11R3_HEM.svs
output mode: hematoxylin
channel name: Hematoxylin
moving images:
- filename: 20210101/skin_case_356_HEM_C01R1_PD1.svs
output mode: aec
channel name: PD-1
- filename: 20210101/skin_case_356_HEM_C01R2_PDL1.svs
output mode: aec
channel name: PD-L1
```
To show the configuration schema, run the following command
```bash
palom-svs show schema
```
### Use the helper script to generate the configuration file
[A helper
script](https://github.com/Yu-AnChen/palom/blob/main/palom/cli/helper.py) is
included showing how to automatically generate the configuration file if the SVS
files are organized and have specific naming pattern.
Here's an example directory containing many SVS files
```
Y:\DATA\SARDANA\MIHC\768473\RAW
CBB_SARDANA_768473_C04R1_CD8.svs
KB_SARDANA_768473_C01R1_PD1.svs
KB_SARDANA_768473_C01R2_PDL1.svs
KB_SARDANA_768473_C01R3_Hem.svs
KB_SARDANA_768473_C02R1_CD4.svs
KB_SARDANA_768473_C03R1_CD3.svs
KB_SARDANA_768473_C03R3_DCLAMP.svs
```
Running the following command to generate the configuration file
```bash
palom-svs-helper -i "Y:\DATA\SARDANA\MIHC\768473\RAW" -n "*Hem*" -o "Y:\DATA\SARDANA\MIHC\768473\RAW\palom\768473.ome.tif" -c "Y:\DATA\SARDANA\MIHC\768473\768473.yml"
```
And the resulting `Y:\DATA\SARDANA\MIHC\768473\768473.yml` file
```yaml
input dir: Y:\DATA\SARDANA\MIHC\768473\RAW
output full path: Y:\DATA\SARDANA\MIHC\768473\RAW\palom\768473.ome.tif
reference image:
filename: .\KB_SARDANA_768473_C01R3_Hem.svs
output mode: hematoxylin
channel name: Hem-C01R3
moving images:
- filename: .\KB_SARDANA_768473_C01R1_PD1.svs
output mode: aec
channel name: PD1-C01R1
- filename: .\KB_SARDANA_768473_C01R2_PDL1.svs
output mode: aec
channel name: PDL1-C01R2
- filename: .\KB_SARDANA_768473_C02R1_CD4.svs
output mode: aec
channel name: CD4-C02R1
- filename: .\KB_SARDANA_768473_C03R1_CD3.svs
output mode: aec
channel name: CD3-C03R1
- filename: .\KB_SARDANA_768473_C03R3_DCLAMP.svs
output mode: aec
channel name: DCLAMP-C03R3
- filename: .\CBB_SARDANA_768473_C04R1_CD8.svs
output mode: aec
channel name: CD8-C04R1
```
After reviewing the configuration file, process those SVS files by running
```bash
palom-svs run -c "Y:\DATA\SARDANA\MIHC\768473\768473.yml"
```
When the process is finished, a pyramidal OME-TIFF file will be generated along
with PNG files showing the feature-based registration results and a log file.
```
Y:\DATA\SARDANA\MIHC\768473\RAW
│ CBB_SARDANA_768473_C04R1_CD8.svs
│ KB_SARDANA_768473_C01R1_PD1.svs
│ KB_SARDANA_768473_C01R2_PDL1.svs
│ KB_SARDANA_768473_C01R3_Hem.svs
│ KB_SARDANA_768473_C02R1_CD4.svs
│ KB_SARDANA_768473_C03R1_CD3.svs
│ KB_SARDANA_768473_C03R3_DCLAMP.svs
│
└───palom
│ 768473.ome.tif
│
└───qc
01-KB_SARDANA_768473_C01R1_PD1.svs.png
02-KB_SARDANA_768473_C01R2_PDL1.svs.png
03-KB_SARDANA_768473_C02R1_CD4.svs.png
04-KB_SARDANA_768473_C03R1_CD3.svs.png
05-KB_SARDANA_768473_C03R3_DCLAMP.svs.png
06-CBB_SARDANA_768473_C04R1_CD8.svs.png
768473.ome.tif.log
```
---
## Scripting
__WARNING__ API may change in the future
### For SVS files
```python
import palom
c1r = palom.reader.SvsReader(r'Y:\DATA\SARDANA\MIHC\75684\GG_TNP_75684_D21_C11R3_HEM.svs')
c2r = palom.reader.SvsReader(r'Y:\DATA\SARDANA\MIHC\75684\GG_TNP_75684_D23_C01R1_PD1.svs')
LEVEL = 1
THUMBNAIL_LEVEL = 2
c1rp = palom.color.PyramidHaxProcessor(c1r.pyramid, thumbnail_level=THUMBNAIL_LEVEL)
c2rp = palom.color.PyramidHaxProcessor(c2r.pyramid, thumbnail_level=THUMBNAIL_LEVEL)
c21l = palom.align.Aligner(
c1rp.get_processed_color(LEVEL),
c2rp.get_processed_color(LEVEL),
ref_thumbnail=c1rp.get_processed_color(THUMBNAIL_LEVEL).compute(),
moving_thumbnail=c2rp.get_processed_color(THUMBNAIL_LEVEL).compute(),
ref_thumbnail_down_factor=c1r.level_downsamples[THUMBNAIL_LEVEL] / c1r.level_downsamples[LEVEL],
moving_thumbnail_down_factor=c2r.level_downsamples[THUMBNAIL_LEVEL] / c2r.level_downsamples[LEVEL]
)
c21l.coarse_register_affine()
c21l.compute_shifts()
c21l.constrain_shifts()
c21l.block_affine_matrices_da
c2m = palom.align.block_affine_transformed_moving_img(
c1rp.get_processed_color(LEVEL),
c2rp.get_processed_color(LEVEL, 'aec'),
mxs=c21l.block_affine_matrices_da
)
palom.pyramid.write_pyramid(
[c2m],
r"Y:\DATA\SARDANA\MIHC\75684\mosaic.ome.tif",
pixel_size=c1r.pixel_size*c1r.level_downsamples[LEVEL],
)
```
### For TIFF and OME-TIFF files
```python
import palom
# reference image is a multichannel immunofluoroscence imaging
c1r = palom.reader.OmePyramidReader(r"Z:\P37_Pilot2\P37_S12_Full.ome.tiff")
# moving image is a brightfield imaging (H&E staining) of the same tissue
# section as the reference image
c2r = palom.reader.OmePyramidReader(r"Z:\P37_Pilot2\HE\P37_S12_E033_93_HE.ome.tiff")
# use second-to-the-bottom pyramid level for a quick test; set `LEVEL = 0` for
# processing lowest level pyramid (full resolution)
LEVEL = 1
# choose thumbnail pyramid level for feature-based affine registration as
# initial coarse alignment
# `THUMBNAIL_LEVEL = c1r.get_thumbnail_level_of_size(2000)` might be a good
# starting point
THUMBNAIL_LEVEL = 3
c21l = palom.align.Aligner(
# use the first channel (Hoechst staining) in the reference image as the
# registration reference
ref_img=c1r.read_level_channels(LEVEL, 0),
# use the second channel (G channel) in the moving image, it usually has
# better contrast
moving_img=c2r.read_level_channels(LEVEL, 1),
# select the same channels for the thumbnail images
ref_thumbnail=c1r.read_level_channels(THUMBNAIL_LEVEL, 0).compute(),
moving_thumbnail=c2r.read_level_channels(THUMBNAIL_LEVEL, 1).compute(),
# specify the downsizing factors so that the affine matrix can be scaled to
# match the registration reference
ref_thumbnail_down_factor=c1r.level_downsamples[THUMBNAIL_LEVEL] / c1r.level_downsamples[LEVEL],
moving_thumbnail_down_factor=c2r.level_downsamples[THUMBNAIL_LEVEL] / c2r.level_downsamples[LEVEL]
)
# run feature-based affine registration using thumbnails
c21l.coarse_register_affine(n_keypoints=4000)
# after coarsly affine registered, run phase correlation on each of the
# corresponding chunks (blocks/pieces) to refine translations
c21l.compute_shifts()
# discard incorrect shifts which is usually due to low contrast in the
# background regions; this is needed for WSI but maybe not for ROI images
c21l.constrain_shifts()
# configure the transformation of aligning the moving image to the registration
# reference
c2m = palom.align.block_affine_transformed_moving_img(
ref_img=c1r.read_level_channels(LEVEL, 0),
# select all the three channels (RGB) in moving image to transform
moving_img=c2r.pyramid[LEVEL],
mxs=c21l.block_affine_matrices_da
)
# write the registered images to a pyramidal ome-tiff
palom.pyramid.write_pyramid(
mosaics=[
# select only the first three channels in referece image to be written
# to the output ome-tiff; for writing all channels, use
# `c1r.pyramid[LEVEL]` instead
c1r.read_level_channels(LEVEL, [0, 1, 2]),
c2m
],
output_path=r"Z:\P37_Pilot2\mosaic.ome.tif",
pixel_size=c1r.pixel_size*c1r.level_downsamples[LEVEL]
)
```
Raw data
{
"_id": null,
"home_page": "https://pypi.org/project/palom/",
"name": "palom",
"maintainer": null,
"docs_url": null,
"requires_python": "<4.0.0,>=3.7.8",
"maintainer_email": null,
"keywords": "microscopy, multiplex imaging, image registration, digital pathology, atlas",
"author": "Yu-An Chen",
"author_email": "atwood12@gmail.com",
"download_url": "https://files.pythonhosted.org/packages/cf/ca/c6d35804eb34e86f8decdea2621f55e3a797f9ae76405882ef4ec2479808/palom-2024.12.1.tar.gz",
"platform": null,
"description": "<h2>\n <img alt=\"palom\" height=\"60\" src=\"palom-logo.svg\">\n <br>\n Piecewise alignment for layers of mosaics\n</h2>\n\nPalom started as a tool for registering [whole-slide\nimages](https://en.wikipedia.org/wiki/Digital_pathology) of the same [FFPE\nsection](https://en.wikipedia.org/wiki/Histology#Sample_preparation) with\ndifferent [IHC stainings](https://en.wikipedia.org/wiki/Immunohistochemistry).\n\n---\n\n## Installation\n\nInstalling palom in a fresh conda environment is recommended. [Instruction for\ninstalling miniconda](https://docs.conda.io/en/latest/miniconda.html)\n\n### Step 1\n\nCreate a named conda environment - _palom_, in the following example, and activate the environment.\n\n```\nconda create -n palom python=3.10 pip -c conda-forge\nconda activate palom\n```\n\n### Step 2\n\nInstall openslide in the conda environment.\n\n- For MacOS, use conda-forge channel\n\n```\nconda install openslide -c conda-forge\n```\n\n- For Windows and Linux, use sdvillal channel\n\n```\nconda install openslide -c sdvillal\n```\n\n### Step 3\n\nInstall palom from pypi in the conda environment.\n\n```\npython -m pip install palom\n```\n\n---\n\n## CLI usage\n\n### Configuration YAML file\n\nPalom CLI tool merges multiple SVS files into a pyramidal OME-TIFF file, with\nthe option to perform preset stain separation (5 modes are available - `output\nmode`: `hematoxylin`, `aec`, `dab`, `grayscale`, `color`)\n\nA user-defined configuration YAML file is required for the run. A configuration\nexample can be printed to the console by running\n\n```bash\npalom-svs show example\n```\n\n```yaml\ninput dir: Y:\\user\\me\\projects\\data\\mihc\noutput full path: Y:\\user\\me\\projects\\analysis\\mihc\\2021\\skin-case-356.ome.tif\n\nreference image:\n filename: 20210111/skin_case_356_HEM_C11R3_HEM.svs\n output mode: hematoxylin\n channel name: Hematoxylin\n\nmoving images:\n- filename: 20210101/skin_case_356_HEM_C01R1_PD1.svs\n output mode: aec\n channel name: PD-1\n- filename: 20210101/skin_case_356_HEM_C01R2_PDL1.svs\n output mode: aec\n channel name: PD-L1\n```\n\nTo show the configuration schema, run the following command\n\n```bash\npalom-svs show schema\n```\n\n### Use the helper script to generate the configuration file\n\n[A helper\nscript](https://github.com/Yu-AnChen/palom/blob/main/palom/cli/helper.py) is\nincluded showing how to automatically generate the configuration file if the SVS\nfiles are organized and have specific naming pattern.\n\nHere's an example directory containing many SVS files\n\n```\nY:\\DATA\\SARDANA\\MIHC\\768473\\RAW\n CBB_SARDANA_768473_C04R1_CD8.svs\n KB_SARDANA_768473_C01R1_PD1.svs\n KB_SARDANA_768473_C01R2_PDL1.svs\n KB_SARDANA_768473_C01R3_Hem.svs\n KB_SARDANA_768473_C02R1_CD4.svs\n KB_SARDANA_768473_C03R1_CD3.svs\n KB_SARDANA_768473_C03R3_DCLAMP.svs\n```\n\nRunning the following command to generate the configuration file\n\n```bash\npalom-svs-helper -i \"Y:\\DATA\\SARDANA\\MIHC\\768473\\RAW\" -n \"*Hem*\" -o \"Y:\\DATA\\SARDANA\\MIHC\\768473\\RAW\\palom\\768473.ome.tif\" -c \"Y:\\DATA\\SARDANA\\MIHC\\768473\\768473.yml\"\n```\n\nAnd the resulting `Y:\\DATA\\SARDANA\\MIHC\\768473\\768473.yml` file\n\n```yaml\ninput dir: Y:\\DATA\\SARDANA\\MIHC\\768473\\RAW\noutput full path: Y:\\DATA\\SARDANA\\MIHC\\768473\\RAW\\palom\\768473.ome.tif\nreference image:\n filename: .\\KB_SARDANA_768473_C01R3_Hem.svs\n output mode: hematoxylin\n channel name: Hem-C01R3\nmoving images:\n- filename: .\\KB_SARDANA_768473_C01R1_PD1.svs\n output mode: aec\n channel name: PD1-C01R1\n- filename: .\\KB_SARDANA_768473_C01R2_PDL1.svs\n output mode: aec\n channel name: PDL1-C01R2\n- filename: .\\KB_SARDANA_768473_C02R1_CD4.svs\n output mode: aec\n channel name: CD4-C02R1\n- filename: .\\KB_SARDANA_768473_C03R1_CD3.svs\n output mode: aec\n channel name: CD3-C03R1\n- filename: .\\KB_SARDANA_768473_C03R3_DCLAMP.svs\n output mode: aec\n channel name: DCLAMP-C03R3\n- filename: .\\CBB_SARDANA_768473_C04R1_CD8.svs\n output mode: aec\n channel name: CD8-C04R1\n```\n\nAfter reviewing the configuration file, process those SVS files by running\n\n```bash\npalom-svs run -c \"Y:\\DATA\\SARDANA\\MIHC\\768473\\768473.yml\"\n```\n\nWhen the process is finished, a pyramidal OME-TIFF file will be generated along\nwith PNG files showing the feature-based registration results and a log file.\n\n```\nY:\\DATA\\SARDANA\\MIHC\\768473\\RAW\n\u2502 CBB_SARDANA_768473_C04R1_CD8.svs\n\u2502 KB_SARDANA_768473_C01R1_PD1.svs\n\u2502 KB_SARDANA_768473_C01R2_PDL1.svs\n\u2502 KB_SARDANA_768473_C01R3_Hem.svs\n\u2502 KB_SARDANA_768473_C02R1_CD4.svs\n\u2502 KB_SARDANA_768473_C03R1_CD3.svs\n\u2502 KB_SARDANA_768473_C03R3_DCLAMP.svs\n\u2502\n\u2514\u2500\u2500\u2500palom\n \u2502 768473.ome.tif\n \u2502\n \u2514\u2500\u2500\u2500qc\n 01-KB_SARDANA_768473_C01R1_PD1.svs.png\n 02-KB_SARDANA_768473_C01R2_PDL1.svs.png\n 03-KB_SARDANA_768473_C02R1_CD4.svs.png\n 04-KB_SARDANA_768473_C03R1_CD3.svs.png\n 05-KB_SARDANA_768473_C03R3_DCLAMP.svs.png\n 06-CBB_SARDANA_768473_C04R1_CD8.svs.png\n 768473.ome.tif.log\n```\n\n---\n\n## Scripting\n\n__WARNING__ API may change in the future\n\n### For SVS files\n\n```python\nimport palom\n\nc1r = palom.reader.SvsReader(r'Y:\\DATA\\SARDANA\\MIHC\\75684\\GG_TNP_75684_D21_C11R3_HEM.svs')\nc2r = palom.reader.SvsReader(r'Y:\\DATA\\SARDANA\\MIHC\\75684\\GG_TNP_75684_D23_C01R1_PD1.svs')\n\nLEVEL = 1\nTHUMBNAIL_LEVEL = 2\n\nc1rp = palom.color.PyramidHaxProcessor(c1r.pyramid, thumbnail_level=THUMBNAIL_LEVEL)\nc2rp = palom.color.PyramidHaxProcessor(c2r.pyramid, thumbnail_level=THUMBNAIL_LEVEL)\n\nc21l = palom.align.Aligner(\n c1rp.get_processed_color(LEVEL),\n c2rp.get_processed_color(LEVEL),\n ref_thumbnail=c1rp.get_processed_color(THUMBNAIL_LEVEL).compute(),\n moving_thumbnail=c2rp.get_processed_color(THUMBNAIL_LEVEL).compute(),\n ref_thumbnail_down_factor=c1r.level_downsamples[THUMBNAIL_LEVEL] / c1r.level_downsamples[LEVEL],\n moving_thumbnail_down_factor=c2r.level_downsamples[THUMBNAIL_LEVEL] / c2r.level_downsamples[LEVEL]\n)\n\nc21l.coarse_register_affine()\nc21l.compute_shifts()\nc21l.constrain_shifts()\n\nc21l.block_affine_matrices_da\n\nc2m = palom.align.block_affine_transformed_moving_img(\n c1rp.get_processed_color(LEVEL),\n c2rp.get_processed_color(LEVEL, 'aec'),\n mxs=c21l.block_affine_matrices_da\n)\n\npalom.pyramid.write_pyramid(\n [c2m],\n r\"Y:\\DATA\\SARDANA\\MIHC\\75684\\mosaic.ome.tif\",\n pixel_size=c1r.pixel_size*c1r.level_downsamples[LEVEL],\n)\n```\n\n### For TIFF and OME-TIFF files\n\n```python\nimport palom\n\n# reference image is a multichannel immunofluoroscence imaging\nc1r = palom.reader.OmePyramidReader(r\"Z:\\P37_Pilot2\\P37_S12_Full.ome.tiff\")\n# moving image is a brightfield imaging (H&E staining) of the same tissue\n# section as the reference image\nc2r = palom.reader.OmePyramidReader(r\"Z:\\P37_Pilot2\\HE\\P37_S12_E033_93_HE.ome.tiff\")\n\n# use second-to-the-bottom pyramid level for a quick test; set `LEVEL = 0` for\n# processing lowest level pyramid (full resolution)\nLEVEL = 1\n# choose thumbnail pyramid level for feature-based affine registration as\n# initial coarse alignment\n# `THUMBNAIL_LEVEL = c1r.get_thumbnail_level_of_size(2000)` might be a good\n# starting point\nTHUMBNAIL_LEVEL = 3\n\nc21l = palom.align.Aligner(\n # use the first channel (Hoechst staining) in the reference image as the\n # registration reference\n ref_img=c1r.read_level_channels(LEVEL, 0),\n # use the second channel (G channel) in the moving image, it usually has\n # better contrast\n moving_img=c2r.read_level_channels(LEVEL, 1),\n # select the same channels for the thumbnail images\n ref_thumbnail=c1r.read_level_channels(THUMBNAIL_LEVEL, 0).compute(),\n moving_thumbnail=c2r.read_level_channels(THUMBNAIL_LEVEL, 1).compute(),\n # specify the downsizing factors so that the affine matrix can be scaled to\n # match the registration reference\n ref_thumbnail_down_factor=c1r.level_downsamples[THUMBNAIL_LEVEL] / c1r.level_downsamples[LEVEL],\n moving_thumbnail_down_factor=c2r.level_downsamples[THUMBNAIL_LEVEL] / c2r.level_downsamples[LEVEL]\n)\n\n# run feature-based affine registration using thumbnails\nc21l.coarse_register_affine(n_keypoints=4000)\n# after coarsly affine registered, run phase correlation on each of the\n# corresponding chunks (blocks/pieces) to refine translations\nc21l.compute_shifts()\n# discard incorrect shifts which is usually due to low contrast in the\n# background regions; this is needed for WSI but maybe not for ROI images\nc21l.constrain_shifts()\n\n# configure the transformation of aligning the moving image to the registration\n# reference\nc2m = palom.align.block_affine_transformed_moving_img(\n ref_img=c1r.read_level_channels(LEVEL, 0),\n # select all the three channels (RGB) in moving image to transform\n moving_img=c2r.pyramid[LEVEL],\n mxs=c21l.block_affine_matrices_da\n)\n\n# write the registered images to a pyramidal ome-tiff\npalom.pyramid.write_pyramid(\n mosaics=[\n # select only the first three channels in referece image to be written\n # to the output ome-tiff; for writing all channels, use\n # `c1r.pyramid[LEVEL]` instead\n c1r.read_level_channels(LEVEL, [0, 1, 2]),\n c2m\n ],\n output_path=r\"Z:\\P37_Pilot2\\mosaic.ome.tif\",\n pixel_size=c1r.pixel_size*c1r.level_downsamples[LEVEL]\n)\n```\n",
"bugtrack_url": null,
"license": null,
"summary": "Piecewise alignment for layers of mosaics",
"version": "2024.12.1",
"project_urls": {
"Homepage": "https://pypi.org/project/palom/",
"Repository": "https://github.com/Yu-AnChen/palom"
},
"split_keywords": [
"microscopy",
" multiplex imaging",
" image registration",
" digital pathology",
" atlas"
],
"urls": [
{
"comment_text": "",
"digests": {
"blake2b_256": "24833dc5c0484422c6995ba890e51ad6167af8ea552a692470a7701a1d3a220c",
"md5": "52ed95b072646e9954da14a1cfbdd2bd",
"sha256": "ff129ddf50f7023ed74974539212f6e1a57a361cfc4ebaeff6760f8451e70565"
},
"downloads": -1,
"filename": "palom-2024.12.1-py3-none-any.whl",
"has_sig": false,
"md5_digest": "52ed95b072646e9954da14a1cfbdd2bd",
"packagetype": "bdist_wheel",
"python_version": "py3",
"requires_python": "<4.0.0,>=3.7.8",
"size": 56292,
"upload_time": "2024-12-19T01:55:33",
"upload_time_iso_8601": "2024-12-19T01:55:33.076892Z",
"url": "https://files.pythonhosted.org/packages/24/83/3dc5c0484422c6995ba890e51ad6167af8ea552a692470a7701a1d3a220c/palom-2024.12.1-py3-none-any.whl",
"yanked": false,
"yanked_reason": null
},
{
"comment_text": "",
"digests": {
"blake2b_256": "cfcac6d35804eb34e86f8decdea2621f55e3a797f9ae76405882ef4ec2479808",
"md5": "c86a9c21306d1139212e71a257e3788e",
"sha256": "71b09da8eff4fd3cfb6fc0a1567251f418dd95e2bca5559de0acf2e544c4ad56"
},
"downloads": -1,
"filename": "palom-2024.12.1.tar.gz",
"has_sig": false,
"md5_digest": "c86a9c21306d1139212e71a257e3788e",
"packagetype": "sdist",
"python_version": "source",
"requires_python": "<4.0.0,>=3.7.8",
"size": 49149,
"upload_time": "2024-12-19T01:55:35",
"upload_time_iso_8601": "2024-12-19T01:55:35.853634Z",
"url": "https://files.pythonhosted.org/packages/cf/ca/c6d35804eb34e86f8decdea2621f55e3a797f9ae76405882ef4ec2479808/palom-2024.12.1.tar.gz",
"yanked": false,
"yanked_reason": null
}
],
"upload_time": "2024-12-19 01:55:35",
"github": true,
"gitlab": false,
"bitbucket": false,
"codeberg": false,
"github_user": "Yu-AnChen",
"github_project": "palom",
"travis_ci": false,
"coveralls": false,
"github_actions": false,
"lcname": "palom"
}