palom


Namepalom JSON
Version 2023.9.2 PyPI version JSON
download
home_pagehttps://pypi.org/project/palom/
SummaryPiecewise alignment for layers of mosaics
upload_time2023-09-15 22:33:35
maintainer
docs_urlNone
authorYu-An Chen
requires_python>=3.7.8,<4.0.0
license
keywords microscopy multiplex imaging image registration digital pathology atlas
VCS
bugtrack_url
requirements No requirements were recorded.
Travis-CI No Travis.
coveralls test coverage No coveralls.
            <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": "",
    "docs_url": null,
    "requires_python": ">=3.7.8,<4.0.0",
    "maintainer_email": "",
    "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/77/a8/f1c1b32ac48e07f423631c09aa52bb00979455ae1c3ac79ab2e39139de7d/palom-2023.9.2.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": "",
    "summary": "Piecewise alignment for layers of mosaics",
    "version": "2023.9.2",
    "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": "8fd83ae69f86ed335b1de2849c4dfa4f5ec30f2b9e7a8322ed2b023da9a9cdc4",
                "md5": "9358d4eaf0ca747566d7dfa40ae8b102",
                "sha256": "a0d70d769c338d1f944912829c051220104809e8f27aae97bc170e8dd8e024c6"
            },
            "downloads": -1,
            "filename": "palom-2023.9.2-py3-none-any.whl",
            "has_sig": false,
            "md5_digest": "9358d4eaf0ca747566d7dfa40ae8b102",
            "packagetype": "bdist_wheel",
            "python_version": "py3",
            "requires_python": ">=3.7.8,<4.0.0",
            "size": 43154,
            "upload_time": "2023-09-15T22:33:33",
            "upload_time_iso_8601": "2023-09-15T22:33:33.099250Z",
            "url": "https://files.pythonhosted.org/packages/8f/d8/3ae69f86ed335b1de2849c4dfa4f5ec30f2b9e7a8322ed2b023da9a9cdc4/palom-2023.9.2-py3-none-any.whl",
            "yanked": false,
            "yanked_reason": null
        },
        {
            "comment_text": "",
            "digests": {
                "blake2b_256": "77a8f1c1b32ac48e07f423631c09aa52bb00979455ae1c3ac79ab2e39139de7d",
                "md5": "e73cdad8b88123a6947a1df0b4ee849d",
                "sha256": "3c893056d3d845543c13cf5b4787f526f1d7f5d49590cfd84da5c493fe831e9c"
            },
            "downloads": -1,
            "filename": "palom-2023.9.2.tar.gz",
            "has_sig": false,
            "md5_digest": "e73cdad8b88123a6947a1df0b4ee849d",
            "packagetype": "sdist",
            "python_version": "source",
            "requires_python": ">=3.7.8,<4.0.0",
            "size": 37868,
            "upload_time": "2023-09-15T22:33:35",
            "upload_time_iso_8601": "2023-09-15T22:33:35.018557Z",
            "url": "https://files.pythonhosted.org/packages/77/a8/f1c1b32ac48e07f423631c09aa52bb00979455ae1c3ac79ab2e39139de7d/palom-2023.9.2.tar.gz",
            "yanked": false,
            "yanked_reason": null
        }
    ],
    "upload_time": "2023-09-15 22:33: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"
}
        
Elapsed time: 0.11519s