Skip to main content

Python bindings for C++ library for reading Prometheus on-disk data

Project description

pypdu

This module provides basic read-only access to the data contained in Prometheus on-disk files from Python.

pypdu may be installed from pip (on linux and macOS):

pip install pypdu

pypdu can optionally expose samples in a numpy array if numpy is installed. If you need this, you can either ensure numpy is installed, or have it pulled in by pypdu as a dependency with:

pip install pypdu[numpy]

Example usage:

#!/usr/bin/env python3

import pypdu

data = pypdu.load("/path/to/stats_data")

for series in data:
    print(series.name) # equivalent to series.labels["__name__"]
    print(series.labels)
    print(len(series.samples)) # number of samples can be computed
                               # without iterating all of them
    for sample in series.samples:
        print(f"{sample.timestamp} : {sample.value}")

Or the series and samples can be unpacked:

for name, labels, samples in data:
    print(name)
    print(labels)
    print(len(samples))
    for timestamp, value in samples:
        print(f"{timestamp} : {value}")

Conversion methods

Manipulating large time series as lists-of-lists is likely to perform poorly in Python. pypdu can expose samples as a thin python wrapper around an underlying C++ type.

This wrapper exposes "list like" operations:

>>> series = data["foobar"]
>>> vector = series.samples.as_vector()
>>> vector[0]
{timestamp=1664592572000, value=0.000000}
>>> vector[0].timestamp
1664592572000

pypdu also provides a convenience to_list(), with the same interface returning pure python types.

These conversions can also apply some common manipulations to the time series:

  • Scaling the timestamps to seconds
series.samples.as_vector(timestamp_units=pypdu.Seconds)
  • Filtering NaN values out of the time series
series.samples.as_vector(filter_nan_values=True)

numpy

If numpy is installed, samples can additionally be accessed as a numpy array. This may avoid copying the samples around if your code expects numpy arrays. E.g.,

for name, labels, samples in data:
    arr = samples.as_array()
    print(arr.dtype)
    print(arr[0])

prints:

dtype([('timestamp', '<i8'), ('value', '<f8')])
(1653556688725, 0.)

as_array() also accepts timestamp_units and filter_nan_values as above.

If numpy is not available at runtime, this will raise an exception:

RuntimeError: Accessing samples as a numpy array requires numpy to be installed

Filtering time series

If only a subset of the time series are desired, pypdu can filter them based on label values, and avoid parsing unneeded series at all:

for series in data.filter({"__name__":"sysproc_page_faults_raw"}):

This will usually perform better than filtering "manually" in python after the fact.

Multiple labels can be specified:

data.filter({"__name__":"sysproc_page_faults_raw", "proc":"memcached"})

ECMAScript regexes can also be used:

data.filter({"proc":pypdu.regex("^go.*")})

Or even arbitrary Python callbacks:

data.filter({"proc":lambda x: x.startswith("go")})

As shorthand, when filtering on __name__ alone, just a string may be provided.

data.filter("sysproc_page_faults_raw")

Single series lookup

If there is only one time series matching your filter, for convenience you can do:

foobar_series = data[{"__name__":"foobar"}]

This is roughly equivalent to:

foobar_series = next(iter(data.filter({"__name__":"foobar"})))

If there are multiple time series matching your filter, this will silently discard all but the lexicographically first (sorted by the key and value of all labels).

If none match, a KeyError is raised.

All types of filter demonstrated above with .filter(...) may be used in this manner also.

Calculations

Simple operations (+ - / *) may be applied to Series objects, computing the result lazily.

a = data["foobar"]
b = data["bazqux"]
c = data["spam"]
expression = (a + b) * (c / 100)
for timestamp, value in expression:
    ...

Note: the resulting iterable will contain a sample at each timestamp seen in any of the constituent series. Even if all series are scraped with the same interval, if they are offset from each other this can lead to a lot of values. To avoid this, the expression can be resampled at a given interval:

for timestamp, value in expression.resample(10000): # 10s in ms
    ...

This will lead to one sample exactly every 10000 milliseconds. No interpolation is performed - if a given series did not have a sample at a chosen instant, the most recent value will be used.

IRate
pypdu.irate(expr)

Results in a Expression which computes the instantaneous rate of change based on the current and previous sample - roughly equivalent to Prometheus irate.

e.g.,

a = data["foobar"]
b = data["bazqux"]
rate = pypdu.irate(a+b/100)
for timestamp, rate_value in rate:
    ....
Sum

As Expression supports addition, the standard Python method sum can be used to add multiple series together.

However, if working with a very large number of series, pypdu.sum may more efficiently construct the Expression result (computation of the summed Samples is identical, however).

e.g.,

series_list = list(data)
py_sum_expr = sum(series_list)
pdu_sum_expr = pypdu.sum(series_list) # may be faster if len(series_list) is large

# but the resulting samples are identical
assert(list(pdu_sum_expr) == list(py_sum_expr))

Histograms

PrometheusData(...).histograms allows iterating all histograms represented by the time series in a data directory.

The histograms are exposed as HistogramTimeSeries, grouping all the component ..._bucket time series together. Indexing into this series provides access to the histogram at a single point in time.

e.g.,

data = pypdu.load("<...>")

for histSeries in data.histograms:
    print("Labels: ", histSeries.labels)
    print("Number of samples: ", len(histSeries))
    for hist in histSeries:
        print("TS: ", hist.timestamp)
        print(hist.buckets())

Iterates over every histogram found in the Prometheus data, then iterates over every sample contained in that time series.

Example output:

Labels:  {'__name__': 'cm_http_requests_seconds', 'instance': 'ns_server', 'job': 'ns_server_high_cardinality'}
Number of samples:  3826
TS:  1621268098827
[(0.001, 8.0), (0.01, 25.0), (0.1, 25.0), (1.0, 25.0), (10.0, 25.0), (inf, 25.0)]
TS:  1621268158827
[(0.001, 39.0), (0.01, 118.0), (0.1, 126.0), (1.0, 127.0), (10.0, 127.0), (inf, 127.0)]
TS:  1621268218827
[(0.001, 43.0), (0.01, 132.0), (0.1, 140.0), (1.0, 141.0), (10.0, 141.0), (inf, 141.0)]
TS:  1621268278827
[(0.001, 48.0), (0.01, 145.0), (0.1, 153.0), (1.0, 154.0), (10.0, 154.0), (inf, 154.0)]
TS:  1621268338827
[(0.001, 53.0), (0.01, 158.0), (0.1, 166.0), (1.0, 167.0), (10.0, 167.0), (inf, 167.0)]
TS:  1621268398827
[(0.001, 55.0), (0.01, 171.0), (0.1, 179.0), (1.0, 180.0), (10.0, 180.0), (inf, 180.0)]
TS:  1621268458827
[(0.001, 60.0), (0.01, 191.0), (0.1, 199.0), (1.0, 200.0), (10.0, 200.0), (inf, 200.0)]
TS:  1621268518827
[(0.001, 66.0), (0.01, 204.0), (0.1, 212.0), (1.0, 213.0), (10.0, 213.0), (inf, 213.0)]
TS:  1621268578827
[(0.001, 71.0), (0.01, 217.0), (0.1, 225.0), (1.0, 226.0), (10.0, 226.0), (inf, 226.0)]
TS:  1621268638827
[(0.001, 73.0), (0.01, 230.0), (0.1, 238.0), (1.0, 239.0), (10.0, 239.0), (inf, 239.0)]
...
Labels: ...

HistogramTimeSeries (in the above example, this is histSeries), can be indexed into - currently only by a sample index, but in the future, selecting the histogram closest to a given timestamp may be supported.

E.g., the first and last point in time view available for a specific histogram can be found with:

first = histSeries[0]
last = histSeries[-1]

From which the timestamp and buckets could be read:

>>> print(last.timestamp) # time since epoch in ms
1631007596974

>>> print(last.bucket_bounds()))
[0.001, 0.01, 0.1, 1.0, 10.0, inf]

>>> print(last.bucket_values())
[4279.0, 4371.0, 4666.0, 5044.0, 5044.0, 5044.0]

>>> print(last.buckets()) # convenience zip of (bounds, values)
[(0.001, 4279.0), (0.01, 4371.0), (0.1, 4666.0), (1.0, 5044.0), (10.0, 5044.0), (inf, 5044.0)]

The difference between histograms at two points in time can also be calculated:

delta = last-first
>>> delta.time_delta
60000
>>> delta.buckets()
[(0.001, 653.0), (0.01, 653.0), (0.1, 653.0), (1.0, 653.0), (10.0, 653.0), (inf, 653.0)]

Or the summation of two histograms:

total = histA+histB
>>> total.buckets()
[(0.001, 1985.0), (0.01, 1985.0), (0.1, 1985.0), (1.0, 1985.0), (10.0, 1985.0), (inf, 1985.0)]

For either of addition or subtraction, the bucket boundaries must exactly match.

Serialisation

Time series may be dumped individually to a file or bytes. This may be useful if you need to store some number of series (e.g., in a key-value store), but don't wish to retain the entire Prometheus data directory.

pypdu.dump/pypdu.load take an int file descriptor or, for convenience, a file-like object supporting fileLike.fileno() -> int.

These methods be used to read/write data from/to a pipe or socket, not just a file on disk. Note, arbitrary file-like objects which are not backed by a file descriptor are not supported.

If provided a file handle which actually refers to a file on disk, load will try to mmap the file. If this fails, it will fall back to reading it like a stream. If mmapping is not desired, it can be disabled with:

pypdu.load(fileDescriptor, allow_mmap=False)

When loading many series from a stream (socket, pipe, etc), the underlying data for all Series will be read into memory - this may be costly if there are many Series. pypdu.load_lazy can instead be used to consume Series from a stream, one at a time.

for series in pypdu.load_lazy(someSocket):
    # series are read and deserialised on demand while iterating

pypdu.dumps creates a bytes object, while pypdu.loads operates on a buffer. Anything supporting the buffer protocol exposing a contiguous buffer may be used. This includes bytes objects, but also numpy arrays and many other types.

A memoryview may be used to slice a buffer, allowing deserialisation from part of a buffer, without having to copy out the relevant bytes.

# fd : int or file-like object with .fileno() method

pypdu.dump(fd, series)
pypdu.dump(fd, [series, series, ...])
pypdu.dump(fd, PrometheusData)

# note, dumps on a lot of series will consume a lot of memory building
# a big bytes object
pypdu.dumps(series) -> bytes
pypdu.dumps([series, series, ...]) -> bytes
pypdu.dumps(PrometheusData) -> bytes

# result of load{,s} depends on what was written
# Deserialised series are entirely in-memory, may consume a lot of
# memory.
pypdu.load(fd) -> Series
pypdu.load(fd) -> [Series, Series,...]

pypdu.loads(buffer) -> Series
pypdu.loads(buffer) -> [Series, Series, ...]

# when loading a lot of series, this is the advised way to avoid
# holding them all in memory at the same time
pypdu.load_lazy(fd) -> Iterable

Example dumping and loading multiple series to/from a file:

to_serialise = []
for series in pypdu.load("foobar/baz/stats_data"):
    if some_condition(series):
        to_serialise.append(series)

with open("somefile", "wb") as f:
    pypdu.dump(f, to_serialise)
...
with open("somefile", "rb") as f:
    for series in pypdu.load_lazy(f):
        # do something with the loaded series

Example dumping and loading a single series to/from stdin/out:

data = pypdu.load("foobar/baz/stats_data")
series = data["foobar_series_name"]
pypdu.dump(sys.stdout, series)

...

series = pypdu.load(sys.stdin)

pypdu.json

For performance, pypdu provides a json encoder capable of efficiently dumping pypdu types. It can also dump typical python types (everything supported by the builtin json), but is not a drop in replacement in terms of arguments.

data = pypdu.load(...)
series = data["foobar"]
pypdu.json.dumps(series)

will produce:

{
    "metric": {
        "__name__": "some_metric_name",
        "label_foo": "label_foo_value",
    },
    "values": [
        [
            1664592572000,
            0.0
        ],
        [
            1664592582000,
            0.0
        ],
        [
            1664592592000,
            0.0
        ],

dumps also supports samples, sample vectors, and expressions:

>>> pypdu.json.dumps(series.samples)
"[[1664592572000, 0.0], [1664592582000, 0.0],...]"
>>> pypdu.json.dumps(series.samples.as_vector(timestamp_units=pypdu.Seconds))
"[[1664592572, 0.0], [1664592582, 0.0],...]"
>>> pypdu.json.dumps((series + 1) * 2)
"[[1664592572000, 2.0], [1664592582000, 2.0],...]"
>>> pypdu.json.dumps(((series + 1) * 2).as_vector(timestamp_units=pypdu.Seconds))
"[[1664592572, 2.0], [1664592582, 2.0],...]"

XOR Chunks

For specific use cases, access to the raw XOR encoded (chunk documentation) chunk data may be required.

To find the chunk objects for a given series:

>>> data = pypdu.load("some_stats_dir")
>>> series = data["foobar_series_name"]
>>> series.chunks
[<pypdu.Chunk object at 0x11c29c270>, <pypdu.Chunk object at 0x11c29dbb0>, ...]

To access the XOR encoded sample data:

>>> chunk = series.chunks[0]
# without copying
>>> memoryview(chunk)
<memory at 0x11c227880>
# with a copy into a python bytes object
>>> chunk.as_bytes()
b'\x00y\xc8\xe0\x8e\...'

Most users will not need to do this as samples can be read from a pypdu.Series(), with the chunks handled transparently.

Runtime version checking

The pypdu version can be specified at install time (e.g., in requirements.txt), but you can also verify the correct version is available at runtime (maybe someone is building locally and forgot to update some dependencies!).

>>> import pypdu
>>> pypdu.__version__
'0.0.12a3'
>>> pypdu.__git_rev__
'a096f0d'
>>> pypdu.__git_tag__
''
>>> pypdu.require(0, 0, 0)
>>> pypdu.require(0, 0, 12)
>>> pypdu.require(0, 1, 0)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
RuntimeError: Current pypdu version 0.0.12a3 does not meet required 0.1.0
>>> pypdu.require(0, 0, 12, "a3")
>>> pypdu.require(0, 0, 12, "a4")
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
RuntimeError: Current pypdu version 0.0.12a3 does not meet required 0.0.12a4

If using a feature introduced in version X.Y.Z, pypdu.require(X, Y, Z) will raise an exception if an older version is in use. This exception can be caught, if you want to provide a more specific error message (e.g., "Remember to update dependencies by running ...").

Alternative installation steps

pip install from source

If a wheel is not available for your platform or architecture, pypdu can be built and installed with:

pip install git+https://github.com/jameseh96/pdu.git

or for a specific version:

pip install git+https://github.com/jameseh96/pdu.git@vX.Y.Z
e.g.,
pip install git+https://github.com/jameseh96/pdu.git@v0.0.19

Building pypdu will require the dependencies listed in the installation instructions.

pypdu is relatively platform independent, but has not been tested on platforms/architectures that don't have a wheel built (e.g., Windows, MacOS+Apple Silicon) - be prepared for potential issues at build and runtime.

setup.py

pypdu may be installed without pip. To use, clone the repository as in the installation instructions.

Then run:

python setup.py install
manual .so

Alternatively, following the cmake steps in the installation instructions to build the project produces a module with a platform-dependent name - for example on MacOS this may be pypdu.cpython-39-darwin.so.

This can be found either in <build dir>/src/pypdu or in your chosen installation prefix. This can be used without installing with setup.py, simply ensure the containing directory is in your PYTHONPATH.

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

pypdu-0.1.10.tar.gz (843.2 kB view details)

Uploaded Source

Built Distributions

pypdu-0.1.10-pp310-pypy310_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl (648.1 kB view details)

Uploaded PyPy manylinux: glibc 2.17+ x86-64

pypdu-0.1.10-pp310-pypy310_pp73-macosx_10_15_x86_64.whl (551.3 kB view details)

Uploaded PyPy macOS 10.15+ x86-64

pypdu-0.1.10-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl (648.3 kB view details)

Uploaded PyPy manylinux: glibc 2.17+ x86-64

pypdu-0.1.10-pp39-pypy39_pp73-macosx_10_15_x86_64.whl (551.4 kB view details)

Uploaded PyPy macOS 10.15+ x86-64

pypdu-0.1.10-pp38-pypy38_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl (648.2 kB view details)

Uploaded PyPy manylinux: glibc 2.17+ x86-64

pypdu-0.1.10-pp38-pypy38_pp73-macosx_10_9_x86_64.whl (551.4 kB view details)

Uploaded PyPy macOS 10.9+ x86-64

pypdu-0.1.10-cp313-cp313-musllinux_1_1_x86_64.whl (1.1 MB view details)

Uploaded CPython 3.13 musllinux: musl 1.1+ x86-64

pypdu-0.1.10-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl (649.3 kB view details)

Uploaded CPython 3.13 manylinux: glibc 2.17+ x86-64

pypdu-0.1.10-cp313-cp313-macosx_11_0_arm64.whl (510.4 kB view details)

Uploaded CPython 3.13 macOS 11.0+ ARM64

pypdu-0.1.10-cp313-cp313-macosx_10_13_x86_64.whl (559.4 kB view details)

Uploaded CPython 3.13 macOS 10.13+ x86-64

pypdu-0.1.10-cp312-cp312-musllinux_1_1_x86_64.whl (1.1 MB view details)

Uploaded CPython 3.12 musllinux: musl 1.1+ x86-64

pypdu-0.1.10-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl (649.3 kB view details)

Uploaded CPython 3.12 manylinux: glibc 2.17+ x86-64

pypdu-0.1.10-cp312-cp312-macosx_11_0_arm64.whl (510.4 kB view details)

Uploaded CPython 3.12 macOS 11.0+ ARM64

pypdu-0.1.10-cp312-cp312-macosx_10_13_x86_64.whl (559.4 kB view details)

Uploaded CPython 3.12 macOS 10.13+ x86-64

pypdu-0.1.10-cp311-cp311-musllinux_1_1_x86_64.whl (1.1 MB view details)

Uploaded CPython 3.11 musllinux: musl 1.1+ x86-64

pypdu-0.1.10-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl (648.7 kB view details)

Uploaded CPython 3.11 manylinux: glibc 2.17+ x86-64

pypdu-0.1.10-cp311-cp311-macosx_11_0_arm64.whl (506.0 kB view details)

Uploaded CPython 3.11 macOS 11.0+ ARM64

pypdu-0.1.10-cp311-cp311-macosx_10_9_x86_64.whl (551.1 kB view details)

Uploaded CPython 3.11 macOS 10.9+ x86-64

pypdu-0.1.10-cp310-cp310-musllinux_1_1_x86_64.whl (1.1 MB view details)

Uploaded CPython 3.10 musllinux: musl 1.1+ x86-64

pypdu-0.1.10-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl (649.0 kB view details)

Uploaded CPython 3.10 manylinux: glibc 2.17+ x86-64

pypdu-0.1.10-cp310-cp310-macosx_11_0_arm64.whl (506.0 kB view details)

Uploaded CPython 3.10 macOS 11.0+ ARM64

pypdu-0.1.10-cp310-cp310-macosx_10_9_x86_64.whl (551.1 kB view details)

Uploaded CPython 3.10 macOS 10.9+ x86-64

pypdu-0.1.10-cp39-cp39-musllinux_1_1_x86_64.whl (1.1 MB view details)

Uploaded CPython 3.9 musllinux: musl 1.1+ x86-64

pypdu-0.1.10-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl (649.1 kB view details)

Uploaded CPython 3.9 manylinux: glibc 2.17+ x86-64

pypdu-0.1.10-cp39-cp39-macosx_11_0_arm64.whl (506.4 kB view details)

Uploaded CPython 3.9 macOS 11.0+ ARM64

pypdu-0.1.10-cp39-cp39-macosx_10_9_x86_64.whl (551.0 kB view details)

Uploaded CPython 3.9 macOS 10.9+ x86-64

pypdu-0.1.10-cp38-cp38-musllinux_1_1_x86_64.whl (1.1 MB view details)

Uploaded CPython 3.8 musllinux: musl 1.1+ x86-64

pypdu-0.1.10-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl (648.6 kB view details)

Uploaded CPython 3.8 manylinux: glibc 2.17+ x86-64

pypdu-0.1.10-cp38-cp38-macosx_11_0_arm64.whl (505.9 kB view details)

Uploaded CPython 3.8 macOS 11.0+ ARM64

pypdu-0.1.10-cp38-cp38-macosx_10_9_x86_64.whl (550.9 kB view details)

Uploaded CPython 3.8 macOS 10.9+ x86-64

File details

Details for the file pypdu-0.1.10.tar.gz.

File metadata

  • Download URL: pypdu-0.1.10.tar.gz
  • Upload date:
  • Size: 843.2 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/5.1.1 CPython/3.12.7

File hashes

Hashes for pypdu-0.1.10.tar.gz
Algorithm Hash digest
SHA256 31dd0bb659992fc192dbc8ef22fb281bcd70ad7c50412e35ff5a1a86fbf9d2e7
MD5 cd398f86d36a35e1c7890cb6c73aadfe
BLAKE2b-256 267cebbe3592a9716abd5f574bbce1aef1aa56700d6916cbc80999cec810e4e9

See more details on using hashes here.

File details

Details for the file pypdu-0.1.10-pp310-pypy310_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl.

File metadata

File hashes

Hashes for pypdu-0.1.10-pp310-pypy310_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl
Algorithm Hash digest
SHA256 a81837b0dcc6000ff0acab46eeb9ac71b8278c9ad053c380fd8d6ac0e5247852
MD5 573d72a0b0e610f2364a9cc78f7cd284
BLAKE2b-256 93e186adf59f191ad7b194b080d3501257eebaeb1d5ad6d0b0fd04c63656a996

See more details on using hashes here.

File details

Details for the file pypdu-0.1.10-pp310-pypy310_pp73-macosx_10_15_x86_64.whl.

File metadata

File hashes

Hashes for pypdu-0.1.10-pp310-pypy310_pp73-macosx_10_15_x86_64.whl
Algorithm Hash digest
SHA256 5588c87965d389e28a8feeed43d732db248779a7b0a5fe9034fd667de41cbdc6
MD5 bc47964b1e6465bb639cb85a031b2f71
BLAKE2b-256 6bb4d38d442e5e4b6df62f1598ca226967b4fa4e8667befaea6c04971583e23e

See more details on using hashes here.

File details

Details for the file pypdu-0.1.10-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl.

File metadata

File hashes

Hashes for pypdu-0.1.10-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl
Algorithm Hash digest
SHA256 0bb4714f502285a8b07017206a8be1c32b19bdd47990b44e9182ac624e62c042
MD5 973d0cca7af58a51add7f866985b2e26
BLAKE2b-256 5efe9c0a10d95f801cf430e53e088c2b162bb5c3d7649fddb9457a6302b22e08

See more details on using hashes here.

File details

Details for the file pypdu-0.1.10-pp39-pypy39_pp73-macosx_10_15_x86_64.whl.

File metadata

File hashes

Hashes for pypdu-0.1.10-pp39-pypy39_pp73-macosx_10_15_x86_64.whl
Algorithm Hash digest
SHA256 67e0ff0c36a22368307a771a79ac0d6cc30c150511120ccd6070a39aec0a9e68
MD5 b42c4c1e13d232a83b8a7bb94aa68575
BLAKE2b-256 d47cc08eb024c31eb4447193e78e138b3730f24f3c6b5ca5d69d28acc543aab0

See more details on using hashes here.

File details

Details for the file pypdu-0.1.10-pp38-pypy38_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl.

File metadata

File hashes

Hashes for pypdu-0.1.10-pp38-pypy38_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl
Algorithm Hash digest
SHA256 7ae60482a3056cbe4fe08e4b561ddf41a195dbeb88c8bdf0ff753f364799dd86
MD5 711e957c72b342dbdee108b37fdfd9e8
BLAKE2b-256 24730200b14a5644a412d9a546a5d6759e713abb01031068eb0bd1b017b188d1

See more details on using hashes here.

File details

Details for the file pypdu-0.1.10-pp38-pypy38_pp73-macosx_10_9_x86_64.whl.

File metadata

File hashes

Hashes for pypdu-0.1.10-pp38-pypy38_pp73-macosx_10_9_x86_64.whl
Algorithm Hash digest
SHA256 6fd0ec74a9e4fc55b0039faf1cd6541b0a4d374703abd4ccadaffb4752e3e0ab
MD5 0f7f0382eb9567b42cdbfd810572825f
BLAKE2b-256 76a50018d55705c961cbd2ca48855976f5d541d54463c2af75fc65d330fb63fd

See more details on using hashes here.

File details

Details for the file pypdu-0.1.10-cp313-cp313-musllinux_1_1_x86_64.whl.

File metadata

File hashes

Hashes for pypdu-0.1.10-cp313-cp313-musllinux_1_1_x86_64.whl
Algorithm Hash digest
SHA256 dd14ec69ca4d32f3f45d691a215b5ac57e33c405ae140640c7e51af40a836208
MD5 dc0aba915e4e7c1105dc17b6516e0cc7
BLAKE2b-256 493600d8cc18e7a6ca58dc51d496a2d1e04fa7e8fe7a16e54d0e3d3889fd2470

See more details on using hashes here.

File details

Details for the file pypdu-0.1.10-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl.

File metadata

File hashes

Hashes for pypdu-0.1.10-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl
Algorithm Hash digest
SHA256 749e91aa71b4fe84c0d62301db40a1326adcd21c4572a95c98ffdc2afe9e6892
MD5 32cb8f19cea17ef7e3cb3a58346b9cb5
BLAKE2b-256 007339e39754961f7d9672de17b0e046c710f7fd6dbd123e927fe95dc11fb037

See more details on using hashes here.

File details

Details for the file pypdu-0.1.10-cp313-cp313-macosx_11_0_arm64.whl.

File metadata

File hashes

Hashes for pypdu-0.1.10-cp313-cp313-macosx_11_0_arm64.whl
Algorithm Hash digest
SHA256 1756897c480039025fae80ab18af0fbc1d219b545aaf6bc45a7660c74e4e8612
MD5 6b6ac5ec638afd59e8c2298b63a31d38
BLAKE2b-256 9fcc4f1cd39149bd8c68959f9bd912810f5609413bbc3632c06895d3b68e1673

See more details on using hashes here.

File details

Details for the file pypdu-0.1.10-cp313-cp313-macosx_10_13_x86_64.whl.

File metadata

File hashes

Hashes for pypdu-0.1.10-cp313-cp313-macosx_10_13_x86_64.whl
Algorithm Hash digest
SHA256 fdbeab76868a846898a8c9b272a0d21ad94d2b102f3f15b860dc9a4bfa6a8af4
MD5 390de95f5efd5f7c678f725a830a0372
BLAKE2b-256 5747cca6cd4a1eb1f1fd2bbd9868cc899f3456e59e1f24c77cd18870207d11de

See more details on using hashes here.

File details

Details for the file pypdu-0.1.10-cp312-cp312-musllinux_1_1_x86_64.whl.

File metadata

File hashes

Hashes for pypdu-0.1.10-cp312-cp312-musllinux_1_1_x86_64.whl
Algorithm Hash digest
SHA256 cbcf268bf51f1b04c3e04a164a5a6d9d9f1492470e8b0406eda63efb8902286c
MD5 4a12cbf5a66653d8964c513c1213c049
BLAKE2b-256 7d3b982b0a45206446eb5d606f30de2ae8072c5fbe61cd52aace6e37a6d99828

See more details on using hashes here.

File details

Details for the file pypdu-0.1.10-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl.

File metadata

File hashes

Hashes for pypdu-0.1.10-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl
Algorithm Hash digest
SHA256 c1096020ae467de1ac8c915a96fbc138dadcb45cf9f181b574bdf9c691785f9b
MD5 43e7723605a689a9bac409effbd26725
BLAKE2b-256 3c9c7e1086e14ef3f5585f3860ec1711cf406e034de94686c010a4c8065bf27a

See more details on using hashes here.

File details

Details for the file pypdu-0.1.10-cp312-cp312-macosx_11_0_arm64.whl.

File metadata

File hashes

Hashes for pypdu-0.1.10-cp312-cp312-macosx_11_0_arm64.whl
Algorithm Hash digest
SHA256 803d884450fe01e3c30a29d93c23aeac0f37870741e682aa9949e893b5c4c97e
MD5 b65897c5f4cfcbbc163b3de091e41a96
BLAKE2b-256 5517ab222c2424054febcee07d979c5074cd16358be7c55974dc7728fbd48044

See more details on using hashes here.

File details

Details for the file pypdu-0.1.10-cp312-cp312-macosx_10_13_x86_64.whl.

File metadata

File hashes

Hashes for pypdu-0.1.10-cp312-cp312-macosx_10_13_x86_64.whl
Algorithm Hash digest
SHA256 e0592490b3c4ffc64d5e93ac4ecd6a431007d10161de5615e06602048c90dff6
MD5 bd40018c33d2141079acc35d0b43a5d3
BLAKE2b-256 7ec309d5f79761783a8dda5348a1ba060d3a0cf9e2c0b46c959b4194124bc069

See more details on using hashes here.

File details

Details for the file pypdu-0.1.10-cp311-cp311-musllinux_1_1_x86_64.whl.

File metadata

File hashes

Hashes for pypdu-0.1.10-cp311-cp311-musllinux_1_1_x86_64.whl
Algorithm Hash digest
SHA256 3229e6380b7ef9ef0821d802053bfc34bf6ec8a464ca6e90980ae0de7f53ed5b
MD5 24e682d3138a309cd8188985a8da118e
BLAKE2b-256 ca6bd1e97f9a1081ffe0f61f0303e83d53eea7adf78ed922944991747a0b6220

See more details on using hashes here.

File details

Details for the file pypdu-0.1.10-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl.

File metadata

File hashes

Hashes for pypdu-0.1.10-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl
Algorithm Hash digest
SHA256 0765b5cd3818ed7f2c70bc351201f116d9b98607e98fcd56878a1180b261d87d
MD5 ac2c68aaef9c8125f0c055c2fc7f94c1
BLAKE2b-256 1dec54dbc53e802fea2bb7f40003271d15118875e5391729f566bde39bd457f8

See more details on using hashes here.

File details

Details for the file pypdu-0.1.10-cp311-cp311-macosx_11_0_arm64.whl.

File metadata

File hashes

Hashes for pypdu-0.1.10-cp311-cp311-macosx_11_0_arm64.whl
Algorithm Hash digest
SHA256 ff471a403a6b7d942feb8a183b49e16da573e0989812cbf432f85a9cd3c47430
MD5 892a91d4b1b32378a283c7cf53b81b07
BLAKE2b-256 9d34402ad5f7ad76e51269dc290356a34b7f4915862c63977eecf8b197cea5f6

See more details on using hashes here.

File details

Details for the file pypdu-0.1.10-cp311-cp311-macosx_10_9_x86_64.whl.

File metadata

File hashes

Hashes for pypdu-0.1.10-cp311-cp311-macosx_10_9_x86_64.whl
Algorithm Hash digest
SHA256 d1c01d844ce3765982918ae121ccabf63ea2852de7e91f5ed4d1901b9a9ce755
MD5 46c2a6e4cfb09f8061ce71f3bf4e9d3d
BLAKE2b-256 6de9579d35fa681ce84bce5d0460ff3a4806079766a6c2d3b7da2f35964ac260

See more details on using hashes here.

File details

Details for the file pypdu-0.1.10-cp310-cp310-musllinux_1_1_x86_64.whl.

File metadata

File hashes

Hashes for pypdu-0.1.10-cp310-cp310-musllinux_1_1_x86_64.whl
Algorithm Hash digest
SHA256 6f52d66f66ca53a2655f2596911c003ea764ebe8680beccdd8e31b14dcd8a39c
MD5 b20522cb2525c050eaa5934e13fc25a3
BLAKE2b-256 9e0d3733d89f6ad54d77ae39e883731c1476448a9ed5e7aaf6b7b1315733abd1

See more details on using hashes here.

File details

Details for the file pypdu-0.1.10-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl.

File metadata

File hashes

Hashes for pypdu-0.1.10-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl
Algorithm Hash digest
SHA256 987d15753b51ce6045b2561b4f0cb961d8f500d19a281860c2e4169bdef3283b
MD5 78123e0c55b9cc449b996d61b6797128
BLAKE2b-256 e5643c6cf067c0be93816255bf56e88c9208f13757265cf46cc77e9284618b40

See more details on using hashes here.

File details

Details for the file pypdu-0.1.10-cp310-cp310-macosx_11_0_arm64.whl.

File metadata

File hashes

Hashes for pypdu-0.1.10-cp310-cp310-macosx_11_0_arm64.whl
Algorithm Hash digest
SHA256 bf0aa1c558329602e8d9e31a73726a2d771a8a4889096e32e41a9a46ea29c18f
MD5 fb32a23f09d809604a2304a793035605
BLAKE2b-256 16c2985109b06d342996d894dc6ce3ed8d95d62aca1f19ac77bb727e6fc42f1c

See more details on using hashes here.

File details

Details for the file pypdu-0.1.10-cp310-cp310-macosx_10_9_x86_64.whl.

File metadata

File hashes

Hashes for pypdu-0.1.10-cp310-cp310-macosx_10_9_x86_64.whl
Algorithm Hash digest
SHA256 0ad490fb8e85575628f38f832d0f3396ca846a73831a39348025ce0aef62406f
MD5 4e534c44498726dc1b74c81839a8cc7e
BLAKE2b-256 56ce5b5ebd4a122ab84d43ab0f8b86894696393e2e36fcccc9eb2a7201cb3c71

See more details on using hashes here.

File details

Details for the file pypdu-0.1.10-cp39-cp39-musllinux_1_1_x86_64.whl.

File metadata

File hashes

Hashes for pypdu-0.1.10-cp39-cp39-musllinux_1_1_x86_64.whl
Algorithm Hash digest
SHA256 fd2fffb422215f84b8c8042fa21a72c662d97665bf96b0f2b2384771bf36acfe
MD5 2680cac90fff90eaba082a6329ca031c
BLAKE2b-256 d83b0fc7a82de8d08ef4b0f81166f1e140134d7dc66729ad32d556e3b32db1d8

See more details on using hashes here.

File details

Details for the file pypdu-0.1.10-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl.

File metadata

File hashes

Hashes for pypdu-0.1.10-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl
Algorithm Hash digest
SHA256 982b96344ec5c1e5b1f5df6feb2f6477a4a12e15872c17bedcf20dc3eb59f3a7
MD5 2221abe0bac3b67d2386a6cc606ceae4
BLAKE2b-256 49c3cca0261935c95b226edb5364e796e52e172fd5ce36cbbbbe807c92793ae8

See more details on using hashes here.

File details

Details for the file pypdu-0.1.10-cp39-cp39-macosx_11_0_arm64.whl.

File metadata

File hashes

Hashes for pypdu-0.1.10-cp39-cp39-macosx_11_0_arm64.whl
Algorithm Hash digest
SHA256 92e3485cd2a931c5b0d0ad2b83740d31a6ba4a96292769c48c5ebbdeb139bc16
MD5 6229d60047211c07497b80b262f8a6b3
BLAKE2b-256 2cc2585240c9f858d1b14572108f00e33900f2ea287276780353cbfc7c1b41de

See more details on using hashes here.

File details

Details for the file pypdu-0.1.10-cp39-cp39-macosx_10_9_x86_64.whl.

File metadata

File hashes

Hashes for pypdu-0.1.10-cp39-cp39-macosx_10_9_x86_64.whl
Algorithm Hash digest
SHA256 f8ded9907289d0287135e157d40bf12cb9e06f8d99f016fe14fb70d4d5bf9851
MD5 8ee79ccf7399f02c2342c1f0b186b890
BLAKE2b-256 80eb4bc8e6d906f9832a1527eaa074b57bf124485297c9815459538a7ae9b35b

See more details on using hashes here.

File details

Details for the file pypdu-0.1.10-cp38-cp38-musllinux_1_1_x86_64.whl.

File metadata

File hashes

Hashes for pypdu-0.1.10-cp38-cp38-musllinux_1_1_x86_64.whl
Algorithm Hash digest
SHA256 df30436b277fb4a295e5355820faeb49acad48500d4ead31eca084ca0d14926b
MD5 06925c1e22dc23f7ddcb027ee73e4876
BLAKE2b-256 af10b360c37f179f2719315fab55c14a3a25eb10c2a5ff083042618086d16b33

See more details on using hashes here.

File details

Details for the file pypdu-0.1.10-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl.

File metadata

File hashes

Hashes for pypdu-0.1.10-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl
Algorithm Hash digest
SHA256 fa9a908640af7d0e93196a32129853125a9c66715a8c6763bea8b3327202c2f5
MD5 de7761ad10efdadf3b304092406f6352
BLAKE2b-256 404308ed8ac7f6b44610f2a0df06c6766c5c5a3bb65d19582be731a8daf8c965

See more details on using hashes here.

File details

Details for the file pypdu-0.1.10-cp38-cp38-macosx_11_0_arm64.whl.

File metadata

File hashes

Hashes for pypdu-0.1.10-cp38-cp38-macosx_11_0_arm64.whl
Algorithm Hash digest
SHA256 8e27035e7de3499466a7091732d111596d9f9729b2e45c2f471566fed3ce8d80
MD5 cbb359cbb70bd5ac2679038449211415
BLAKE2b-256 8c250dd36351336dadfea47ce0f1e5ea988f83a52cee6d7699b0a4c4ecf3097a

See more details on using hashes here.

File details

Details for the file pypdu-0.1.10-cp38-cp38-macosx_10_9_x86_64.whl.

File metadata

File hashes

Hashes for pypdu-0.1.10-cp38-cp38-macosx_10_9_x86_64.whl
Algorithm Hash digest
SHA256 e9c1a5ceaa256c52039d30243c4f3479d8dfb7408eae85be8d6bcf0fda753933
MD5 d11a6520404fcca51ae2b8ce513677b5
BLAKE2b-256 4a8c451a56987518bdd8fae22f5c6ac3cbf0ddcf25549f4891460d4dd1f97613

See more details on using hashes here.

Supported by

AWS AWS Cloud computing and Security Sponsor Datadog Datadog Monitoring Fastly Fastly CDN Google Google Download Analytics Microsoft Microsoft PSF Sponsor Pingdom Pingdom Monitoring Sentry Sentry Error logging StatusPage StatusPage Status page