rusterize


Namerusterize JSON
Version 0.4.0 PyPI version JSON
download
home_pageNone
SummaryHigh performance rasterization tool for Python built in Rust
upload_time2025-08-05 23:06:29
maintainerNone
docs_urlNone
authorNone
requires_python>=3.11
licenseNone
keywords rust fast raster geometry geopandas xarray
VCS
bugtrack_url
requirements No requirements were recorded.
Travis-CI No Travis.
coveralls test coverage No coveralls.
            # rusterize

High performance rasterization tool for Python built in Rust. This
repository stems from the [fasterize](https://github.com/ecohealthalliance/fasterize.git) package built in C++
for R and ports parts of the logics into Python with a Rust backend, in addition to some useful improvements (see [API](#API)).

**rusterize** is designed to work on *(multi)polygons* and *(multi)linestrings*, even when they are nested inside complex geometry collections. Functionally, it takes an input [geopandas](https://geopandas.org/en/stable/) dataframe and returns a [xarray](https://docs.xarray.dev/en/stable/). 

# Installation

Install the current version with pip:

``` shell
pip install rusterize
```

# Contributing

Any contribution is welcome! You can install **rusterize** directly
from this repo using [maturin](https://www.maturin.rs/) as an editable
package. For this to work, you’ll need to have [Rust](https://www.rust-lang.org/tools/install) and
[cargo](https://doc.rust-lang.org/cargo/getting-started/installation.html)
installed.

``` shell
# Clone repo
git clone https://github.com/<username>/rusterize.git
cd rusterize

# Install the Rust nightly toolchain
rustup toolchain install nightly-2025-07-31

 # Install maturin
pip install maturin

# Install editable version with optmized code
maturin develop --profile dist-release
```

# API

This package has a simple API:

``` python
from rusterize import rusterize

# gdf = <import/modify dataframe as needed>

# rusterize
rusterize(gdf,
          res=(30, 30),
          out_shape=(10, 10)
          extent=(0, 10, 10, 20)
          field="field",
          by="by",
          burn=None,
          fun="sum",
          background=0,
          dtype="uint8") 
```

- `gdf`: geopandas dataframe to rasterize
- `res`: (xres, yres) for desired resolution (default: `None`)
- `out_shape`: (nrows, ncols) for desired output shape (default: `None`)
- `extent`: (xmin, ymin, xmax, ymax) for desired output extent (default: `None`)
- `field`: column to rasterize. Mutually exclusive with `burn`. (default: `None` -> a value of `1` is rasterized)
- `by`: column for grouping. Assign each group to a band in the stack. Values are taken from `field` if specified, else `burn` is rasterized. (default: `None` -> singleband raster)
- `burn`: a single value to burn. Mutually exclusive with `field`. (default: `None`). If no field is found in `gdf` or if `field` is `None`, then `burn=1`
- `fun`: pixel function to use when multiple values overlap. Available options are `sum`, `first`, `last`, `min`, `max`, `count`, or `any`. (default: `last`)
- `background`: background value in final raster. (default: `np.nan`). A `None` value corresponds to the default of the specified dtype. An illegal value for a dtype will be replaced with the default of that dtype. For example, a `background=np.nan` for `dtype="uint8"` will become `background=0`, where `0` is the default for `uint8`.
- `dtype`: dtype of the final raster. Possible values are `uint8`, `uint16`, `uint32`, `uint64`, `int8`, `int16`, `int32`, `int64`, `float32`, `float64` (default: `float64`)

Note that control over the desired extent is not as strict as for resolution and shape. That is,
when resolution, output shape, and extent are specified, priority is given to resolution and shape.
So, extent is not guaranteed, but resolution and shape are. If extent is not given, it is taken
from the polygons and is not modified, unless you specify a resolution value. If you only specify an output
shape, the extent is maintained. This mimics the logics of `gdal_rasterize`.

# Usage

**rusterize** consists of a single function `rusterize()`. The Rust implementation
returns a dictionary that is converted to a xarray on the Python side
for simpliicty.

``` python
from rusterize import rusterize
import geopandas as gpd
from shapely import wkt
import matplotlib.pyplot as plt

# Construct geometries
geoms = [
    "POLYGON ((-180 -20, -140 55, 10 0, -140 -60, -180 -20), (-150 -20, -100 -10, -110 20, -150 -20))",
    "POLYGON ((-10 0, 140 60, 160 0, 140 -55, -10 0))",
    "POLYGON ((-125 0, 0 60, 40 5, 15 -45, -125 0))",
    "MULTILINESTRING ((-180 -70, -140 -50), (-140 -50, -100 -70), (-100 -70, -60 -50), (-60 -50, -20 -70), (-20 -70, 20 -50), (20 -50, 60 -70), (60 -70, 100 -50), (100 -50, 140 -70), (140 -70, 180 -50))",
    "GEOMETRYCOLLECTION (POINT (50 -40), POLYGON ((75 -40, 75 -30, 100 -30, 100 -40, 75 -40)), LINESTRING (80 -40, 100 0), GEOMETRYCOLLECTION (POLYGON ((100 20, 100 30, 110 30, 110 20, 100 20))))"
]

# Convert WKT strings to Shapely geometries
geometries = [wkt.loads(geom) for geom in geoms]

# Create a GeoDataFrame
gdf = gpd.GeoDataFrame({'value': range(1, len(geoms) + 1)}, geometry=geometries, crs='EPSG:32619')

# rusterize
output = rusterize(
    gdf,
    res=(1, 1),
    field="value",
    fun="sum",
).squeeze()

# plot it
fig, ax = plt.subplots(figsize=(12, 6))
output.plot.imshow(ax=ax)
plt.show()
```

![](img/plot.png)

# Benchmarks

**rusterize** is fast! Let’s try it on small and large datasets.

``` python
from rusterize import rusterize
import geopandas as gpd
import requests
import zipfile
from io import BytesIO

# large dataset (~380 MB)
url = "https://s3.amazonaws.com/hp3-shapefiles/Mammals_Terrestrial.zip"
response = requests.get(url)

# unzip
with zipfile.ZipFile(BytesIO(response.content), 'r') as zip_ref:
    zip_ref.extractall()
    
# read
gdf_large = gpd.read_file("Mammals_Terrestrial/Mammals_Terrestrial.shp")

# small dataset (first 1000 rows)
gdf_small = gdf_large.iloc[:1000, :]

# rusterize at 1/6 degree resolution
def test_large(benchmark):
  benchmark(rusterize, gdf_large, res=(1/6, 1/6), fun="sum")
   
def test_small(benchmark):
  benchmark(rusterize, gdf_small, res=(1/6, 1/6), fun="sum")  
```

Then you can run it with [pytest](https://docs.pytest.org/en/stable/) and [pytest-benchmark](https://pytest-benchmark.readthedocs.io/en/stable/):
```
pytest <python file> --benchmark-min-rounds=20 --benchmark-time-unit='s'

--------------------------------------------- benchmark: 1 tests --------------------------------------------
Name (time in s)         Min      Max     Mean  StdDev   Median     IQR  Outliers     OPS  Rounds  Iterations
-------------------------------------------------------------------------------------------------------------
rusterize_small       0.0791    0.0899   0.0812  0.0027   0.0803  0.0020       2;2  12.3214     20          1
rusterize_large     1.379545    1.4474   1.4006  0.0178   1.3966  0.0214       5;1   0.7140     20          1
-------------------------------------------------------------------------------------------------------------
```
And fasterize:
``` r
library(sf)
library(raster)
library(fasterize)
library(microbenchmark)

large <- st_read("Mammals_Terrestrial/Mammals_Terrestrial.shp", quiet = TRUE)
small <- large[1:1000, ]
fn <- function(v) {
  r <- raster(v, res = 1/6)
  return(fasterize(v, r, fun = "sum"))
}
microbenchmark(
  fasterize_large = f <- fn(large),
  fasterize_small = f <- fn(small),
  times=20L,
  unit='s'
)
```
```
Unit: seconds
            expr       min         lq       mean     median        uq        max neval
 fasterize_small 0.4741043  0.4926114  0.5191707  0.5193289  0.536741  0.5859029    20
 fasterize_large 9.2199426 10.3595465 10.6653139 10.5369429 11.025771 11.7944567    20
```
And on an even larger datasets? Here we use a layer from the province of Quebec, Canada representing ~2M polygons of forest stands, rasterized at 30 meters (20 rounds) with no field value and pixel function `any`. The comparison with `gdal_rasterize` was run with `hyperfine --runs 20 "gdal_rasterize -tr 30 30 -burn 1 <data_in> <data_out>"`.
```
# rusterize
--------------------------------------------- benchmark: 1 tests --------------------------------------------
Name (time in s)         Min      Max     Mean  StdDev   Median     IQR  Outliers     OPS  Rounds  Iterations
-------------------------------------------------------------------------------------------------------------
rusterize             5.9331   7.2308   6.1302  0.3183  5.9903   0.1736       2;4  0.1631      20           1
-------------------------------------------------------------------------------------------------------------

# fasterize
Unit: seconds
      expr      min       lq     mean   median       uq      max neval
 fasterize 157.4734 177.2055 194.3222 194.6455 213.9195 230.6504    20

# gdal_rasterize (CLI) - read from fast drive, write to fast drive
Time (mean ± σ):      5.495 s ±  0.038 s    [User: 4.268 s, System: 1.225 s]
Range (min … max):    5.452 s …  5.623 s    20 runs
```
In terms of (multi)line rasterization speed, here's a benchmark against `gdal_rasterize` using a layer from the province of Quebec, Canada, representing a subset of the road network for a total of ~535K multilinestrings.
```
# rusterize
--------------------------------------------- benchmark: 1 tests --------------------------------------------
Name (time in s)         Min      Max     Mean  StdDev   Median     IQR  Outliers     OPS  Rounds  Iterations
-------------------------------------------------------------------------------------------------------------
test                  4.5272   5.9488   4.7171  0.3236   4.6360  0.1680       2;2  0.2120      20           1
-------------------------------------------------------------------------------------------------------------

# gdal_rasterize (CLI) - read from fast drive, write to fast drive
Time (mean ± σ):      8.719 s ±  0.063 s    [User: 3.782 s, System: 4.917 s]
Range (min … max):    8.658 s …  8.874 s    20 runs
```
# Comparison with other tools

While **rusterize** is fast, there are other fast alternatives out there, including `GDAL`, `rasterio` and `geocube`. However, **rusterize** allows for a seamless, Rust-native processing with similar or lower memory footprint that doesn't require you to leave Python, and returns the geoinformation you need for downstream processing with ample control over resolution, shape, extent, and data type.

The following is a time comparison on a single run on the same forest stands dataset used earlier.
```
rusterize:    5.9 sec
rasterio:     68  sec (but no spatial information)
fasterize:    157 sec (including raster creation)
geocube:      260 sec (larger memory footprint)
```

            

Raw data

            {
    "_id": null,
    "home_page": null,
    "name": "rusterize",
    "maintainer": null,
    "docs_url": null,
    "requires_python": ">=3.11",
    "maintainer_email": null,
    "keywords": "rust, fast, raster, geometry, geopandas, xarray",
    "author": null,
    "author_email": null,
    "download_url": "https://files.pythonhosted.org/packages/f1/14/2d5e9e1a2220cdd67a0cbb6b73633323cbb3a9d0ceb113a3c7308e8c8f45/rusterize-0.4.0.tar.gz",
    "platform": null,
    "description": "# rusterize\n\nHigh performance rasterization tool for Python built in Rust. This\nrepository stems from the [fasterize](https://github.com/ecohealthalliance/fasterize.git) package built in C++\nfor R and ports parts of the logics into Python with a Rust backend, in addition to some useful improvements (see [API](#API)).\n\n**rusterize** is designed to work on *(multi)polygons* and *(multi)linestrings*, even when they are nested inside complex geometry collections. Functionally, it takes an input [geopandas](https://geopandas.org/en/stable/) dataframe and returns a [xarray](https://docs.xarray.dev/en/stable/). \n\n# Installation\n\nInstall the current version with pip:\n\n``` shell\npip install rusterize\n```\n\n# Contributing\n\nAny contribution is welcome! You can install **rusterize** directly\nfrom this repo using [maturin](https://www.maturin.rs/) as an editable\npackage. For this to work, you\u2019ll need to have [Rust](https://www.rust-lang.org/tools/install) and\n[cargo](https://doc.rust-lang.org/cargo/getting-started/installation.html)\ninstalled.\n\n``` shell\n# Clone repo\ngit clone https://github.com/<username>/rusterize.git\ncd rusterize\n\n# Install the Rust nightly toolchain\nrustup toolchain install nightly-2025-07-31\n\n # Install maturin\npip install maturin\n\n# Install editable version with optmized code\nmaturin develop --profile dist-release\n```\n\n# API\n\nThis package has a simple API:\n\n``` python\nfrom rusterize import rusterize\n\n# gdf = <import/modify dataframe as needed>\n\n# rusterize\nrusterize(gdf,\n          res=(30, 30),\n          out_shape=(10, 10)\n          extent=(0, 10, 10, 20)\n          field=\"field\",\n          by=\"by\",\n          burn=None,\n          fun=\"sum\",\n          background=0,\n          dtype=\"uint8\") \n```\n\n- `gdf`: geopandas dataframe to rasterize\n- `res`: (xres, yres) for desired resolution (default: `None`)\n- `out_shape`: (nrows, ncols) for desired output shape (default: `None`)\n- `extent`: (xmin, ymin, xmax, ymax) for desired output extent (default: `None`)\n- `field`: column to rasterize. Mutually exclusive with `burn`. (default: `None` -> a value of `1` is rasterized)\n- `by`: column for grouping. Assign each group to a band in the stack. Values are taken from `field` if specified, else `burn` is rasterized. (default: `None` -> singleband raster)\n- `burn`: a single value to burn. Mutually exclusive with `field`. (default: `None`). If no field is found in `gdf` or if `field` is `None`, then `burn=1`\n- `fun`: pixel function to use when multiple values overlap. Available options are `sum`, `first`, `last`, `min`, `max`, `count`, or `any`. (default: `last`)\n- `background`: background value in final raster. (default: `np.nan`). A `None` value corresponds to the default of the specified dtype. An illegal value for a dtype will be replaced with the default of that dtype. For example, a `background=np.nan` for `dtype=\"uint8\"` will become `background=0`, where `0` is the default for `uint8`.\n- `dtype`: dtype of the final raster. Possible values are `uint8`, `uint16`, `uint32`, `uint64`, `int8`, `int16`, `int32`, `int64`, `float32`, `float64` (default: `float64`)\n\nNote that control over the desired extent is not as strict as for resolution and shape. That is,\nwhen resolution, output shape, and extent are specified, priority is given to resolution and shape.\nSo, extent is not guaranteed, but resolution and shape are. If extent is not given, it is taken\nfrom the polygons and is not modified, unless you specify a resolution value. If you only specify an output\nshape, the extent is maintained. This mimics the logics of `gdal_rasterize`.\n\n# Usage\n\n**rusterize** consists of a single function `rusterize()`. The Rust implementation\nreturns a dictionary that is converted to a xarray on the Python side\nfor simpliicty.\n\n``` python\nfrom rusterize import rusterize\nimport geopandas as gpd\nfrom shapely import wkt\nimport matplotlib.pyplot as plt\n\n# Construct geometries\ngeoms = [\n    \"POLYGON ((-180 -20, -140 55, 10 0, -140 -60, -180 -20), (-150 -20, -100 -10, -110 20, -150 -20))\",\n    \"POLYGON ((-10 0, 140 60, 160 0, 140 -55, -10 0))\",\n    \"POLYGON ((-125 0, 0 60, 40 5, 15 -45, -125 0))\",\n    \"MULTILINESTRING ((-180 -70, -140 -50), (-140 -50, -100 -70), (-100 -70, -60 -50), (-60 -50, -20 -70), (-20 -70, 20 -50), (20 -50, 60 -70), (60 -70, 100 -50), (100 -50, 140 -70), (140 -70, 180 -50))\",\n    \"GEOMETRYCOLLECTION (POINT (50 -40), POLYGON ((75 -40, 75 -30, 100 -30, 100 -40, 75 -40)), LINESTRING (80 -40, 100 0), GEOMETRYCOLLECTION (POLYGON ((100 20, 100 30, 110 30, 110 20, 100 20))))\"\n]\n\n# Convert WKT strings to Shapely geometries\ngeometries = [wkt.loads(geom) for geom in geoms]\n\n# Create a GeoDataFrame\ngdf = gpd.GeoDataFrame({'value': range(1, len(geoms) + 1)}, geometry=geometries, crs='EPSG:32619')\n\n# rusterize\noutput = rusterize(\n    gdf,\n    res=(1, 1),\n    field=\"value\",\n    fun=\"sum\",\n).squeeze()\n\n# plot it\nfig, ax = plt.subplots(figsize=(12, 6))\noutput.plot.imshow(ax=ax)\nplt.show()\n```\n\n![](img/plot.png)\n\n# Benchmarks\n\n**rusterize** is fast! Let\u2019s try it on small and large datasets.\n\n``` python\nfrom rusterize import rusterize\nimport geopandas as gpd\nimport requests\nimport zipfile\nfrom io import BytesIO\n\n# large dataset (~380 MB)\nurl = \"https://s3.amazonaws.com/hp3-shapefiles/Mammals_Terrestrial.zip\"\nresponse = requests.get(url)\n\n# unzip\nwith zipfile.ZipFile(BytesIO(response.content), 'r') as zip_ref:\n    zip_ref.extractall()\n    \n# read\ngdf_large = gpd.read_file(\"Mammals_Terrestrial/Mammals_Terrestrial.shp\")\n\n# small dataset (first 1000 rows)\ngdf_small = gdf_large.iloc[:1000, :]\n\n# rusterize at 1/6 degree resolution\ndef test_large(benchmark):\n  benchmark(rusterize, gdf_large, res=(1/6, 1/6), fun=\"sum\")\n   \ndef test_small(benchmark):\n  benchmark(rusterize, gdf_small, res=(1/6, 1/6), fun=\"sum\")  \n```\n\nThen you can run it with [pytest](https://docs.pytest.org/en/stable/) and [pytest-benchmark](https://pytest-benchmark.readthedocs.io/en/stable/):\n```\npytest <python file> --benchmark-min-rounds=20 --benchmark-time-unit='s'\n\n--------------------------------------------- benchmark: 1 tests --------------------------------------------\nName (time in s)         Min      Max     Mean  StdDev   Median     IQR  Outliers     OPS  Rounds  Iterations\n-------------------------------------------------------------------------------------------------------------\nrusterize_small       0.0791    0.0899   0.0812  0.0027   0.0803  0.0020       2;2  12.3214     20          1\nrusterize_large     1.379545    1.4474   1.4006  0.0178   1.3966  0.0214       5;1   0.7140     20          1\n-------------------------------------------------------------------------------------------------------------\n```\nAnd fasterize:\n``` r\nlibrary(sf)\nlibrary(raster)\nlibrary(fasterize)\nlibrary(microbenchmark)\n\nlarge <- st_read(\"Mammals_Terrestrial/Mammals_Terrestrial.shp\", quiet = TRUE)\nsmall <- large[1:1000, ]\nfn <- function(v) {\n  r <- raster(v, res = 1/6)\n  return(fasterize(v, r, fun = \"sum\"))\n}\nmicrobenchmark(\n  fasterize_large = f <- fn(large),\n  fasterize_small = f <- fn(small),\n  times=20L,\n  unit='s'\n)\n```\n```\nUnit: seconds\n            expr       min         lq       mean     median        uq        max neval\n fasterize_small 0.4741043  0.4926114  0.5191707  0.5193289  0.536741  0.5859029    20\n fasterize_large 9.2199426 10.3595465 10.6653139 10.5369429 11.025771 11.7944567    20\n```\nAnd on an even larger datasets? Here we use a layer from the province of Quebec, Canada representing ~2M polygons of forest stands, rasterized at 30 meters (20 rounds) with no field value and pixel function `any`. The comparison with `gdal_rasterize` was run with `hyperfine --runs 20 \"gdal_rasterize -tr 30 30 -burn 1 <data_in> <data_out>\"`.\n```\n# rusterize\n--------------------------------------------- benchmark: 1 tests --------------------------------------------\nName (time in s)         Min      Max     Mean  StdDev   Median     IQR  Outliers     OPS  Rounds  Iterations\n-------------------------------------------------------------------------------------------------------------\nrusterize             5.9331   7.2308   6.1302  0.3183  5.9903   0.1736       2;4  0.1631      20           1\n-------------------------------------------------------------------------------------------------------------\n\n# fasterize\nUnit: seconds\n      expr      min       lq     mean   median       uq      max neval\n fasterize 157.4734 177.2055 194.3222 194.6455 213.9195 230.6504    20\n\n# gdal_rasterize (CLI) - read from fast drive, write to fast drive\nTime (mean \u00b1 \u03c3):      5.495 s \u00b1  0.038 s    [User: 4.268 s, System: 1.225 s]\nRange (min \u2026 max):    5.452 s \u2026  5.623 s    20 runs\n```\nIn terms of (multi)line rasterization speed, here's a benchmark against `gdal_rasterize` using a layer from the province of Quebec, Canada, representing a subset of the road network for a total of ~535K multilinestrings.\n```\n# rusterize\n--------------------------------------------- benchmark: 1 tests --------------------------------------------\nName (time in s)         Min      Max     Mean  StdDev   Median     IQR  Outliers     OPS  Rounds  Iterations\n-------------------------------------------------------------------------------------------------------------\ntest                  4.5272   5.9488   4.7171  0.3236   4.6360  0.1680       2;2  0.2120      20           1\n-------------------------------------------------------------------------------------------------------------\n\n# gdal_rasterize (CLI) - read from fast drive, write to fast drive\nTime (mean \u00b1 \u03c3):      8.719 s \u00b1  0.063 s    [User: 3.782 s, System: 4.917 s]\nRange (min \u2026 max):    8.658 s \u2026  8.874 s    20 runs\n```\n# Comparison with other tools\n\nWhile **rusterize** is fast, there are other fast alternatives out there, including `GDAL`, `rasterio` and `geocube`. However, **rusterize** allows for a seamless, Rust-native processing with similar or lower memory footprint that doesn't require you to leave Python, and returns the geoinformation you need for downstream processing with ample control over resolution, shape, extent, and data type.\n\nThe following is a time comparison on a single run on the same forest stands dataset used earlier.\n```\nrusterize:    5.9 sec\nrasterio:     68  sec (but no spatial information)\nfasterize:    157 sec (including raster creation)\ngeocube:      260 sec (larger memory footprint)\n```\n",
    "bugtrack_url": null,
    "license": null,
    "summary": "High performance rasterization tool for Python built in Rust",
    "version": "0.4.0",
    "project_urls": {
        "repository": "https://github.com/ttrotto/rusterize"
    },
    "split_keywords": [
        "rust",
        " fast",
        " raster",
        " geometry",
        " geopandas",
        " xarray"
    ],
    "urls": [
        {
            "comment_text": null,
            "digests": {
                "blake2b_256": "29763cd2d7a344bffcdb21068cd75841448a2ce2105bda5a74664e983bdf5a8e",
                "md5": "1c148fc132bc47d29cf80a69445746db",
                "sha256": "bfc5e8173004cdf382ff88034a49e6c6122a43ea280c10a76dae3cb0c4f8e7f6"
            },
            "downloads": -1,
            "filename": "rusterize-0.4.0-cp311-abi3-macosx_10_12_x86_64.whl",
            "has_sig": false,
            "md5_digest": "1c148fc132bc47d29cf80a69445746db",
            "packagetype": "bdist_wheel",
            "python_version": "cp311",
            "requires_python": ">=3.11",
            "size": 14301770,
            "upload_time": "2025-08-05T23:06:11",
            "upload_time_iso_8601": "2025-08-05T23:06:11.068956Z",
            "url": "https://files.pythonhosted.org/packages/29/76/3cd2d7a344bffcdb21068cd75841448a2ce2105bda5a74664e983bdf5a8e/rusterize-0.4.0-cp311-abi3-macosx_10_12_x86_64.whl",
            "yanked": false,
            "yanked_reason": null
        },
        {
            "comment_text": null,
            "digests": {
                "blake2b_256": "01631f0a191428dcfc6d532f708c110d9a586f93bd7f0df1291ca085b3764b0c",
                "md5": "6c7351df2590eaa9ed2719949a7933ed",
                "sha256": "44cd1ca7fd0e2a6fc4a59adac1c9a381788c9b896eab58f00766fc991899048e"
            },
            "downloads": -1,
            "filename": "rusterize-0.4.0-cp311-abi3-macosx_11_0_arm64.whl",
            "has_sig": false,
            "md5_digest": "6c7351df2590eaa9ed2719949a7933ed",
            "packagetype": "bdist_wheel",
            "python_version": "cp311",
            "requires_python": ">=3.11",
            "size": 13169411,
            "upload_time": "2025-08-05T23:06:13",
            "upload_time_iso_8601": "2025-08-05T23:06:13.565382Z",
            "url": "https://files.pythonhosted.org/packages/01/63/1f0a191428dcfc6d532f708c110d9a586f93bd7f0df1291ca085b3764b0c/rusterize-0.4.0-cp311-abi3-macosx_11_0_arm64.whl",
            "yanked": false,
            "yanked_reason": null
        },
        {
            "comment_text": null,
            "digests": {
                "blake2b_256": "109574e481741ae08b8289af90a6ced04b9d0695c722aaa534729bcc7c26ae7b",
                "md5": "bdc9dd141aa39e379ce27d9f1bace8dc",
                "sha256": "3509fc4ed8f03813d39f0de9b214eda04a1e75ae58eaad2bd77204f1ef706b18"
            },
            "downloads": -1,
            "filename": "rusterize-0.4.0-cp311-abi3-manylinux_2_28_aarch64.whl",
            "has_sig": false,
            "md5_digest": "bdc9dd141aa39e379ce27d9f1bace8dc",
            "packagetype": "bdist_wheel",
            "python_version": "cp311",
            "requires_python": ">=3.11",
            "size": 13687201,
            "upload_time": "2025-08-05T23:06:17",
            "upload_time_iso_8601": "2025-08-05T23:06:17.156566Z",
            "url": "https://files.pythonhosted.org/packages/10/95/74e481741ae08b8289af90a6ced04b9d0695c722aaa534729bcc7c26ae7b/rusterize-0.4.0-cp311-abi3-manylinux_2_28_aarch64.whl",
            "yanked": false,
            "yanked_reason": null
        },
        {
            "comment_text": null,
            "digests": {
                "blake2b_256": "0948fdfc217b8166f90f0ccacd9687ab67f6a840d60398c127788b61bfd8ecf6",
                "md5": "28e3f186d50c535691b0ca0f9d93004a",
                "sha256": "fadec5242e0fc0ca55abd26f8da286a6a03692aac30fbcd348326c5d8e95f7bd"
            },
            "downloads": -1,
            "filename": "rusterize-0.4.0-cp311-abi3-manylinux_2_28_armv7l.whl",
            "has_sig": false,
            "md5_digest": "28e3f186d50c535691b0ca0f9d93004a",
            "packagetype": "bdist_wheel",
            "python_version": "cp311",
            "requires_python": ">=3.11",
            "size": 14418089,
            "upload_time": "2025-08-05T23:06:19",
            "upload_time_iso_8601": "2025-08-05T23:06:19.537705Z",
            "url": "https://files.pythonhosted.org/packages/09/48/fdfc217b8166f90f0ccacd9687ab67f6a840d60398c127788b61bfd8ecf6/rusterize-0.4.0-cp311-abi3-manylinux_2_28_armv7l.whl",
            "yanked": false,
            "yanked_reason": null
        },
        {
            "comment_text": null,
            "digests": {
                "blake2b_256": "3c50f1b572aaf2c6fbb43c8cc0a7f3c4636fd80ac3fdce0b1eba48441d358ddb",
                "md5": "27dc8f6d25f329f516c290a055264fd5",
                "sha256": "3397f67350d099ad00a7f3ccb74fb5ff6a354a50ff0a3fadbdc9487bc4d7ea18"
            },
            "downloads": -1,
            "filename": "rusterize-0.4.0-cp311-abi3-manylinux_2_28_ppc64le.whl",
            "has_sig": false,
            "md5_digest": "27dc8f6d25f329f516c290a055264fd5",
            "packagetype": "bdist_wheel",
            "python_version": "cp311",
            "requires_python": ">=3.11",
            "size": 15628475,
            "upload_time": "2025-08-05T23:06:22",
            "upload_time_iso_8601": "2025-08-05T23:06:22.859679Z",
            "url": "https://files.pythonhosted.org/packages/3c/50/f1b572aaf2c6fbb43c8cc0a7f3c4636fd80ac3fdce0b1eba48441d358ddb/rusterize-0.4.0-cp311-abi3-manylinux_2_28_ppc64le.whl",
            "yanked": false,
            "yanked_reason": null
        },
        {
            "comment_text": null,
            "digests": {
                "blake2b_256": "6b0d20165f997be20a21dc0725f86587302434be6dc59b9c8347cc0ecef73fa9",
                "md5": "9496048e2ef062190fed284e1f17edee",
                "sha256": "08354d8e6780505dfc03410b99d32a26176c97efa5013e5a1bb2bf1282adc777"
            },
            "downloads": -1,
            "filename": "rusterize-0.4.0-cp311-abi3-manylinux_2_28_x86_64.whl",
            "has_sig": false,
            "md5_digest": "9496048e2ef062190fed284e1f17edee",
            "packagetype": "bdist_wheel",
            "python_version": "cp311",
            "requires_python": ">=3.11",
            "size": 14721197,
            "upload_time": "2025-08-05T23:06:25",
            "upload_time_iso_8601": "2025-08-05T23:06:25.254827Z",
            "url": "https://files.pythonhosted.org/packages/6b/0d/20165f997be20a21dc0725f86587302434be6dc59b9c8347cc0ecef73fa9/rusterize-0.4.0-cp311-abi3-manylinux_2_28_x86_64.whl",
            "yanked": false,
            "yanked_reason": null
        },
        {
            "comment_text": null,
            "digests": {
                "blake2b_256": "6f841d8b7dacaaeae2ae0c8efed3f86780631cdfd386de937815c9cd2825de03",
                "md5": "0f0219d71f99846c5cf95d682aabd848",
                "sha256": "02b7f7a1052f1ee69dfbb3cb17de6c3af8681610b5f1cd9b06f765540a4a8ace"
            },
            "downloads": -1,
            "filename": "rusterize-0.4.0-cp311-abi3-win_amd64.whl",
            "has_sig": false,
            "md5_digest": "0f0219d71f99846c5cf95d682aabd848",
            "packagetype": "bdist_wheel",
            "python_version": "cp311",
            "requires_python": ">=3.11",
            "size": 14464793,
            "upload_time": "2025-08-05T23:06:27",
            "upload_time_iso_8601": "2025-08-05T23:06:27.310309Z",
            "url": "https://files.pythonhosted.org/packages/6f/84/1d8b7dacaaeae2ae0c8efed3f86780631cdfd386de937815c9cd2825de03/rusterize-0.4.0-cp311-abi3-win_amd64.whl",
            "yanked": false,
            "yanked_reason": null
        },
        {
            "comment_text": null,
            "digests": {
                "blake2b_256": "f1142d5e9e1a2220cdd67a0cbb6b73633323cbb3a9d0ceb113a3c7308e8c8f45",
                "md5": "2725b9f0facdd8582b5ea8e52f2b343a",
                "sha256": "13f59036c53766bf13847f299fcdc1c4218388f6457be0bc14a50c4567ff9d56"
            },
            "downloads": -1,
            "filename": "rusterize-0.4.0.tar.gz",
            "has_sig": false,
            "md5_digest": "2725b9f0facdd8582b5ea8e52f2b343a",
            "packagetype": "sdist",
            "python_version": "source",
            "requires_python": ">=3.11",
            "size": 74377,
            "upload_time": "2025-08-05T23:06:29",
            "upload_time_iso_8601": "2025-08-05T23:06:29.379105Z",
            "url": "https://files.pythonhosted.org/packages/f1/14/2d5e9e1a2220cdd67a0cbb6b73633323cbb3a9d0ceb113a3c7308e8c8f45/rusterize-0.4.0.tar.gz",
            "yanked": false,
            "yanked_reason": null
        }
    ],
    "upload_time": "2025-08-05 23:06:29",
    "github": true,
    "gitlab": false,
    "bitbucket": false,
    "codeberg": false,
    "github_user": "ttrotto",
    "github_project": "rusterize",
    "travis_ci": false,
    "coveralls": false,
    "github_actions": true,
    "lcname": "rusterize"
}
        
Elapsed time: 1.96592s