Skip to main content

High-performance persistent (immutable) data structures for Python

Project description

PyPersistent

A high-performance collection of persistent (immutable) data structures for Python, written in C++.

Features

  • Immutable: All operations return new collections, leaving originals unchanged
  • Structural Sharing: New versions share most structure (O(log n) changes instead of O(n) copies)
  • Fast: 3-5x faster than pyrsistent, with merge operations up to 176x faster
  • Thread-Safe: Immutability makes concurrent access safe without locks
  • Python 3.13+ Free-Threading Ready: Lock-free design with atomic reference counting for true parallelism
  • Memory Efficient: Structural sharing minimizes memory overhead
  • Dual Interface: Both functional (Clojure-style) and Pythonic APIs

Data Structures

PyPersistent provides five core persistent data structures:

PersistentDict

Unordered key-value map based on Hash Array Mapped Trie (HAMT).

  • Use for: General-purpose dictionary needs with immutability
  • Time complexity: O(log₃₂ n) ≈ 6 steps for 1M elements
  • Features: Fast lookups, structural sharing, bulk merge operations
  • Example:
    from pypersistent import PersistentDict
    
    m = PersistentDict.create(name='Alice', age=30)
    m2 = m.set('city', 'NYC')
    m3 = m | {'role': 'developer'}  # Merge
    

PersistentSortedDict

Sorted key-value map based on Left-Leaning Red-Black Tree.

  • Use for: Ordered data, range queries, min/max operations
  • Time complexity: O(log₂ n) for all operations
  • Features: Sorted iteration, range queries (subseq/rsubseq), first/last
  • Example:
    from pypersistent import PersistentSortedDict
    
    m = PersistentSortedDict.from_dict({3: 'c', 1: 'a', 2: 'b'})
    list(m.keys())  # [1, 2, 3] - always sorted
    
    # Range queries
    sub = m.subseq(start=1, end=2, start_inclusive=True, end_inclusive=False)
    list(sub.keys())  # [1]
    
    # Min/max
    m.first()  # (1, 'a')
    m.last()   # (3, 'c')
    

PersistentList

Indexed sequence based on bit-partitioned vector trie (RRB-Tree variant).

  • Use for: Ordered sequences with efficient random access and append
  • Time complexity: O(log₃₂ n) for get/set, O(1) for append
  • Features: Fast indexed access, efficient append, slicing
  • Example:
    from pypersistent import PersistentList
    
    v = PersistentList.create(1, 2, 3)
    v2 = v.conj(4)  # Append
    v3 = v2.assoc(0, 10)  # Update index 0
    v[1]  # 2 - indexed access
    

PersistentSet

Unordered set based on HAMT (same as PersistentDict).

  • Use for: Unique collection of items, set operations
  • Time complexity: O(log₃₂ n) for add/remove/contains
  • Features: Fast membership testing, set operations (union, intersection, difference)
  • Example:
    from pypersistent import PersistentSet
    
    s = PersistentSet.create(1, 2, 3)
    s2 = s.conj(4)  # Add
    s3 = s.disj(2)  # Remove
    2 in s  # True
    

PersistentArrayMap

Small map optimization using array of key-value pairs.

  • Use for: Maps with < 8 entries (automatic optimization)
  • Time complexity: O(n) linear scan, but faster than HAMT for tiny maps
  • Features: Lower memory overhead, faster for very small maps
  • Note: Typically used internally; PersistentDict automatically uses this for small maps

Choosing the Right Data Structure

Need Use Why
General key-value storage PersistentDict Fastest for unordered data
Sorted keys / range queries PersistentSortedDict Maintains sort order, supports ranges
Indexed sequence PersistentList Fast random access and append
Unique items / set operations PersistentSet Membership testing, set algebra
Very small dicts (< 8 items) PersistentArrayMap Lower overhead for tiny dicts

Performance

Why Use Persistent Data Structures?

The key advantage of persistent data structures is structural sharing: when you create a modified version, the new and old versions share most of their internal structure rather than duplicating everything.

Example:

# Python dict - must copy everything
d1 = {i: f'val{i}' for i in range(10000)}
d2 = d1.copy()  # Copies all 10,000 entries
d2['new_key'] = 'new_value'

# PersistentDict - shares structure
from pypersistent import PersistentDict
m1 = PersistentDict.from_dict({i: f'val{i}' for i in range(10000)})
m2 = m1.set('new_key', 'new_value')  # Shares 99.99% of structure with m1

When to Use pypersistent

✅ Use pypersistent when:

  • Creating multiple versions - Undo/redo, snapshots, version history
  • Concurrent access - Multiple threads safely reading shared data without locks
  • Functional programming - Immutable data flow, pure functions
  • Building up collections incrementally - Each addition shares structure with previous version

❌ Use standard Python dict/list when:

  • You only need one mutable version
  • Maximum raw construction speed is critical
  • Extremely memory-constrained environments

Performance vs Python Standard Library

PersistentDict vs dict

Operation pypersistent Python dict Speedup
Structural Sharing (100 variants of 10K dict) 74µs 1.79ms 24x faster 🚀
Structural Sharing (100 variants of 1M dict) 158µs 517ms 3271x faster 🚀
Single lookup 776µs (1K ops) 427µs 1.8x slower
Construction (1M elements) 2.74s 299ms 9x slower

Key insight: Creating multiple versions through structural sharing is 24-3271x faster than copying dicts, with the advantage growing dramatically for larger collections.

PersistentList vs list

Operation pypersistent Python list Speedup
Structural Sharing (100 variants of 10K list) 74µs 1.79ms 24x faster 🚀
Append 100 elements 42µs 2.3µs 18x slower
Random access (100 ops) 13µs 2.7µs 5x slower

Key insight: If you need multiple versions (undo, history), PersistentList is dramatically faster.

Performance vs pyrsistent

pyrsistent is a mature pure-Python library with similar persistent data structures. pypersistent offers better performance through its C++ implementation, but with a smaller feature set.

PersistentDict Performance Comparison

Size Operation pypersistent (C++) pyrsistent (Python) Speedup
100K Merge (50K+50K) 563µs 98.9ms 176x faster 🚀
10K Merge (5K+5K) 155µs 9.12ms 59x faster 🚀
10K Lookup (1K ops) 157µs 476µs 3.0x faster
10K Update (100 ops) 64µs 287µs 4.5x faster
10K Construction 811µs 1.95ms 2.4x faster
10K Iteration 1.27ms 732µs 1.7x slower

Why the difference? pypersistent's C++ implementation provides:

  • Optimized tree traversal and node allocation
  • Cache-friendly memory layout
  • Specialized bulk merge algorithms
  • Direct memory manipulation without Python object overhead

Feature Comparison

Feature pypersistent pyrsistent
PersistentDict (pmap)
PersistentList (pvector)
PersistentSet (pset)
PersistentSortedDict ✅ (pbag)
PersistentArrayMap (small dicts)
PersistentBag (multiset)
PersistentDeque
PersistentRecord/Class
Evolvers (transient mutations)
Freeze/thaw (deep conversion)
Type checking integration

Summary: Choose pypersistent for performance-critical applications with the core data structures. Choose pyrsistent for a richer feature set and pure-Python portability.

Performance by Map Size

Size Construction Lookup (1K ops) Sharing (100 variants)
100 73µs 19µs 77µs
1K 765µs 205µs 95µs
10K 9.7ms 228µs 108µs
100K 110ms 255µs 133µs
1M 2.74s 776ms 158µs

Fast Iteration Methods

For complete iteration over small-medium dicts, use materialized list methods:

m = PersistentDict.from_dict({...})

# Fast methods (1.7-3x faster for dicts < 100K)
items = m.items_list()   # Returns list of (key, value) tuples
keys = m.keys_list()     # Returns list of keys
values = m.values_list() # Returns list of values

# Lazy iterators (better for very large dicts or early exit)
for k, v in m.items():   # Generator, O(log n) memory
    ...

Performance:

  • Dicts ≤ 10K: 3x faster with items_list()
  • Dicts ≤ 100K: 1.7x faster with items_list()
  • Dicts > 100K: Use iterator (lazy, memory-efficient)

Technical Details

Implementation: C++ HAMT (Hash Array Mapped Trie) with:

  • Bottom-up bulk construction for from_dict()
  • Arena allocator for fast node allocation
  • Structural tree merging for merge()
  • COW semantics for collision nodes
  • Fast iteration with pre-allocated lists

Time Complexity: O(log₃₂ n) ≈ 6 steps for 1M elements Space Complexity: O(n) with structural sharing across versions

For detailed performance analysis and benchmarking methodology, see docs/.

Installation

pip install pypersistent

Or build from source:

git clone https://github.com/cmarschner/pypersistent.git
cd pypersistent
python setup.py install

Use Cases

Use persistent data structures when:

  • Creating multiple versions of data (undo/redo, time-travel, version history)
  • Sharing data across threads without locks or defensive copying
  • Functional programming patterns (immutability, pure functions)
  • Creating modified copies is frequent (structural sharing makes this fast)
  • Python 3.13+ free-threading for true parallelism

Use mutable collections when:

  • Single mutable instance is sufficient
  • Maximum raw construction speed is critical
  • Memory per entry is highly constrained

Specific use cases:

  • Config management: Share base config, each thread creates customized version
  • Event sourcing: Maintain history of all states efficiently
  • Reactive programming: Pass immutable state between components
  • Concurrent caching: Multiple threads read/update cache without locks
  • Functional data pipelines: Transform data through pipeline stages

How It Works

PyPersistent implements multiple classic persistent data structures:

PersistentDict - Hash Array Mapped Trie (HAMT)

Based on the HAMT data structure used by Clojure, Scala, and Haskell:

  • 32-way branching tree indexed by hash bits
  • Path copying for immutability
  • Structural sharing between versions
  • std::shared_ptr for entry sharing (44x fewer INCREF/DECREF)
  • Inline storage with std::variant for cache-friendly access

PersistentSortedDict - Left-Leaning Red-Black Tree

Self-balancing binary search tree with:

  • Path copying for immutability
  • Sorted order maintenance (O(log₂ n))
  • Atomic reference counting for node sharing
  • Range query support via tree traversal

PersistentList - Bit-Partitioned Trie

32-way branching tree for indexed access:

  • Path copying for updates
  • Tail optimization for fast append
  • O(log₃₂ n) random access (~6 steps for 1M elements)
  • Efficient slicing via structural sharing

PersistentSet - HAMT-based Set

Uses PersistentDict internally with:

  • Keys as set elements
  • Same O(log₃₂ n) complexity
  • Set algebra operations

PersistentArrayMap - Simple Array

Linear array for tiny dicts (< 8 entries):

  • Lower overhead than HAMT for small sizes
  • O(n) operations but faster than tree for n < 8
  • Automatically used by PersistentDict when beneficial

Technical Details

Complexity:

  • PersistentDict/HashSet: O(log₃₂ n) ≈ 6 steps for 1M elements
  • PersistentSortedDict: O(log₂ n) for all operations
  • PersistentList: O(log₃₂ n) get/set, O(1) append
  • PersistentArrayMap: O(n) but fast for n < 8

Implementation:

  • C++ with pybind11 bindings
  • Atomic reference counting (std::atomic<int>)
  • Structural sharing for memory efficiency
  • Thread-safe reads (fully immutable)

Python 3.13+ Free-Threading Support

PyPersistent is fully compatible with Python 3.13's experimental free-threading mode (nogil), making it ideal for parallel workloads:

Why It Works

  1. Lock-Free Reads: Immutable data structure allows concurrent reads without synchronization
  2. Atomic Reference Counting: Internal C++ reference counting uses std::atomic operations
  3. Thread-Safe Entry Storage: Uses std::shared_ptr with built-in thread-safe reference counting
  4. Independent Updates: Each thread can create new versions without blocking others

Usage with Free-Threading

# Python 3.13+ with --disable-gil or PYTHON_GIL=0
import threading
from pypersistent import PersistentDict

# Shared base dict
base_config = PersistentDict.create(
    api_url='https://api.example.com',
    timeout=30,
    retries=3
)

def process_request(thread_id, data):
    # Each thread creates its own version - no locks needed!
    my_config = base_config.set('thread_id', thread_id)
    my_config = my_config.set('request_data', data)

    # Concurrent reads are completely lock-free
    url = my_config['api_url']
    timeout = my_config['timeout']

    # Do work...
    return my_config

# Spawn threads - true parallelism without GIL!
threads = []
for i in range(100):
    t = threading.Thread(target=process_request, args=(i, f'data_{i}'))
    threads.append(t)
    t.start()

for t in threads:
    t.join()

Performance Benefits

Without the GIL:

  • Parallel reads: Multiple threads read simultaneously without contention
  • Parallel updates: Each thread creates new versions independently
  • No lock overhead: Zero synchronization cost for immutable operations
  • Structural sharing shines: Creating 100 thread-local variants is 3000x faster than copying dicts

Enable Free-Threading

# Python 3.13+
python3.13 --disable-gil your_script.py

# Or set environment variable
export PYTHON_GIL=0
python3.13 your_script.py

Note: Free-threading is experimental in Python 3.13. Some packages may not be compatible yet.

Development

# Install development dependencies
pip install pytest pybind11

# Build extension
python setup.py build_ext --inplace

# Run all tests
pytest -v

# Run specific data structure tests
pytest test_persistent_dict.py -v
pytest test_persistent_sorted_dict.py -v
pytest test_persistent_list.py -v
pytest test_persistent_set.py -v

# Run performance benchmarks
python performance_test.py
python performance_vector.py

License

MIT License - see LICENSE file for details

Credits

Inspired by Clojure's persistent data structures and the HAMT paper by Bagwell (2001).

Implementation by Clemens Marschner.

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

pypersistent-2.0.0b1.tar.gz (65.9 kB view details)

Uploaded Source

Built Distributions

If you're not sure about the file name format, learn more about wheel file names.

pypersistent-2.0.0b1-cp312-cp312-win_amd64.whl (180.4 kB view details)

Uploaded CPython 3.12Windows x86-64

pypersistent-2.0.0b1-cp312-cp312-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl (283.6 kB view details)

Uploaded CPython 3.12manylinux: glibc 2.27+ x86-64manylinux: glibc 2.28+ x86-64

pypersistent-2.0.0b1-cp312-cp312-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl (262.1 kB view details)

Uploaded CPython 3.12manylinux: glibc 2.27+ ARM64manylinux: glibc 2.28+ ARM64

pypersistent-2.0.0b1-cp312-cp312-macosx_11_0_arm64.whl (249.1 kB view details)

Uploaded CPython 3.12macOS 11.0+ ARM64

pypersistent-2.0.0b1-cp312-cp312-macosx_10_9_x86_64.whl (259.6 kB view details)

Uploaded CPython 3.12macOS 10.9+ x86-64

pypersistent-2.0.0b1-cp311-cp311-win_amd64.whl (180.2 kB view details)

Uploaded CPython 3.11Windows x86-64

pypersistent-2.0.0b1-cp311-cp311-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl (286.8 kB view details)

Uploaded CPython 3.11manylinux: glibc 2.27+ x86-64manylinux: glibc 2.28+ x86-64

pypersistent-2.0.0b1-cp311-cp311-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl (266.2 kB view details)

Uploaded CPython 3.11manylinux: glibc 2.27+ ARM64manylinux: glibc 2.28+ ARM64

pypersistent-2.0.0b1-cp311-cp311-macosx_11_0_arm64.whl (248.3 kB view details)

Uploaded CPython 3.11macOS 11.0+ ARM64

pypersistent-2.0.0b1-cp311-cp311-macosx_10_9_x86_64.whl (255.6 kB view details)

Uploaded CPython 3.11macOS 10.9+ x86-64

pypersistent-2.0.0b1-cp310-cp310-win_amd64.whl (179.6 kB view details)

Uploaded CPython 3.10Windows x86-64

pypersistent-2.0.0b1-cp310-cp310-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl (284.3 kB view details)

Uploaded CPython 3.10manylinux: glibc 2.27+ x86-64manylinux: glibc 2.28+ x86-64

pypersistent-2.0.0b1-cp310-cp310-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl (263.9 kB view details)

Uploaded CPython 3.10manylinux: glibc 2.27+ ARM64manylinux: glibc 2.28+ ARM64

pypersistent-2.0.0b1-cp310-cp310-macosx_11_0_arm64.whl (247.4 kB view details)

Uploaded CPython 3.10macOS 11.0+ ARM64

pypersistent-2.0.0b1-cp310-cp310-macosx_10_9_x86_64.whl (254.4 kB view details)

Uploaded CPython 3.10macOS 10.9+ x86-64

File details

Details for the file pypersistent-2.0.0b1.tar.gz.

File metadata

  • Download URL: pypersistent-2.0.0b1.tar.gz
  • Upload date:
  • Size: 65.9 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.7

File hashes

Hashes for pypersistent-2.0.0b1.tar.gz
Algorithm Hash digest
SHA256 c3a484e2a4339a4c56a9ac308e79990cc8d05f26af851869d483777a42778abc
MD5 686a69c0f16835181144e6face28ad4c
BLAKE2b-256 73cc4d9fb7b1f55cf2048f2dd3caf7d2597944099aedd060d882c085fd7a030f

See more details on using hashes here.

Provenance

The following attestation bundles were made for pypersistent-2.0.0b1.tar.gz:

Publisher: build-wheels.yml on cmarschner/pypersistent

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file pypersistent-2.0.0b1-cp312-cp312-win_amd64.whl.

File metadata

File hashes

Hashes for pypersistent-2.0.0b1-cp312-cp312-win_amd64.whl
Algorithm Hash digest
SHA256 dc98d2f74f5566aa525455b54b5c1f886272248189730e4e9ff4494abb403435
MD5 e40c050ad0046138f9b46b84c34a398e
BLAKE2b-256 bdc022995c8185266752397191999ccdc721e7e68fede61f36bb97ae698ef87d

See more details on using hashes here.

Provenance

The following attestation bundles were made for pypersistent-2.0.0b1-cp312-cp312-win_amd64.whl:

Publisher: build-wheels.yml on cmarschner/pypersistent

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file pypersistent-2.0.0b1-cp312-cp312-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl.

File metadata

File hashes

Hashes for pypersistent-2.0.0b1-cp312-cp312-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl
Algorithm Hash digest
SHA256 a9a905f3edfb00c2672f7ca9858780707cc71aae7f2e3b6276375b8dd371fcbc
MD5 7558e66d69cfed0550eb56826cc957c6
BLAKE2b-256 05cb07f66e9b9cccffeb8d5b53d07496be656b5bd8b700d81074e73651d9dff2

See more details on using hashes here.

Provenance

The following attestation bundles were made for pypersistent-2.0.0b1-cp312-cp312-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl:

Publisher: build-wheels.yml on cmarschner/pypersistent

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file pypersistent-2.0.0b1-cp312-cp312-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl.

File metadata

File hashes

Hashes for pypersistent-2.0.0b1-cp312-cp312-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl
Algorithm Hash digest
SHA256 02ccaf90bd67148c9b2ba7cc8faa5b7a9d55598c41bade65c33e5df14daeecd3
MD5 46b174034b2856970412357e95360f32
BLAKE2b-256 d77beaa333a93393da49be58954f774c1db6cc4adfc80c34af519602a8033c7d

See more details on using hashes here.

Provenance

The following attestation bundles were made for pypersistent-2.0.0b1-cp312-cp312-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl:

Publisher: build-wheels.yml on cmarschner/pypersistent

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file pypersistent-2.0.0b1-cp312-cp312-macosx_11_0_arm64.whl.

File metadata

File hashes

Hashes for pypersistent-2.0.0b1-cp312-cp312-macosx_11_0_arm64.whl
Algorithm Hash digest
SHA256 b54714d215a7948f5b6601802a51d81a48dd2dfcae39df78351f3ecc8b71151a
MD5 5e132c46e293067a0fb77c773b37132a
BLAKE2b-256 ff1d9800541b65eeb9b7c7dbf2211da2f754f350a47f03c03e5687f5f83fbe17

See more details on using hashes here.

Provenance

The following attestation bundles were made for pypersistent-2.0.0b1-cp312-cp312-macosx_11_0_arm64.whl:

Publisher: build-wheels.yml on cmarschner/pypersistent

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file pypersistent-2.0.0b1-cp312-cp312-macosx_10_9_x86_64.whl.

File metadata

File hashes

Hashes for pypersistent-2.0.0b1-cp312-cp312-macosx_10_9_x86_64.whl
Algorithm Hash digest
SHA256 75846560ac7b035f6d24c8e2802384298011474cf718948e6fa5d0e809dc8c80
MD5 92eefda6b5a46797b3e72d4e73e34496
BLAKE2b-256 60caaa36170f7e0d8e59be8cf16a4a8711114d0f32be851528c3455198e6bf4b

See more details on using hashes here.

Provenance

The following attestation bundles were made for pypersistent-2.0.0b1-cp312-cp312-macosx_10_9_x86_64.whl:

Publisher: build-wheels.yml on cmarschner/pypersistent

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file pypersistent-2.0.0b1-cp311-cp311-win_amd64.whl.

File metadata

File hashes

Hashes for pypersistent-2.0.0b1-cp311-cp311-win_amd64.whl
Algorithm Hash digest
SHA256 5cc4acf729e057e7c5ef51bb93d897a9906914cfde19f3fd81be8f1c6dc5e0f1
MD5 3e9d32d3f2c53628d06412e569a6fc9e
BLAKE2b-256 ed7ff150e6506ed4a19fcd82afcfb667a8fa7f1b93c94ea2add83780b19ccbde

See more details on using hashes here.

Provenance

The following attestation bundles were made for pypersistent-2.0.0b1-cp311-cp311-win_amd64.whl:

Publisher: build-wheels.yml on cmarschner/pypersistent

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file pypersistent-2.0.0b1-cp311-cp311-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl.

File metadata

File hashes

Hashes for pypersistent-2.0.0b1-cp311-cp311-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl
Algorithm Hash digest
SHA256 63b3fa43baea99b7afcf36d62d361f3882217911bda3c32570938cfed80c4ea0
MD5 2d2f729029e675ba971ce586fa0f28c6
BLAKE2b-256 3b87a33b7cdfef7c60b2cf51893e3af4bcdc36c9523b63db2e3efa128e43140e

See more details on using hashes here.

Provenance

The following attestation bundles were made for pypersistent-2.0.0b1-cp311-cp311-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl:

Publisher: build-wheels.yml on cmarschner/pypersistent

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file pypersistent-2.0.0b1-cp311-cp311-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl.

File metadata

File hashes

Hashes for pypersistent-2.0.0b1-cp311-cp311-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl
Algorithm Hash digest
SHA256 e1ad5d363c4e3059025c5fbb79cd41768ad683208cd105654badd65b963b737e
MD5 114508951a28951c2c6a98a52b618e37
BLAKE2b-256 87f61021b4f80d12c266b713e358f76b8d3f65b7f5720f2a61148f4d568f3ced

See more details on using hashes here.

Provenance

The following attestation bundles were made for pypersistent-2.0.0b1-cp311-cp311-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl:

Publisher: build-wheels.yml on cmarschner/pypersistent

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file pypersistent-2.0.0b1-cp311-cp311-macosx_11_0_arm64.whl.

File metadata

File hashes

Hashes for pypersistent-2.0.0b1-cp311-cp311-macosx_11_0_arm64.whl
Algorithm Hash digest
SHA256 dcde9d99e7a5ca8bd1f75261cd9aeb83a06c113dc9b741f44abde1c3da8f250a
MD5 36f90289163afb1699ce01c7657fe1a5
BLAKE2b-256 390190bd84af33f143419952ed83d7100cd1969678fe2c741e3faa7b2d59bc7c

See more details on using hashes here.

Provenance

The following attestation bundles were made for pypersistent-2.0.0b1-cp311-cp311-macosx_11_0_arm64.whl:

Publisher: build-wheels.yml on cmarschner/pypersistent

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file pypersistent-2.0.0b1-cp311-cp311-macosx_10_9_x86_64.whl.

File metadata

File hashes

Hashes for pypersistent-2.0.0b1-cp311-cp311-macosx_10_9_x86_64.whl
Algorithm Hash digest
SHA256 e805d5e2282d263719fc064643968b9c6fe6b30a149104942c8017d92e5bf10a
MD5 8b13adf340a095ccbf3e8ea5a7942c3c
BLAKE2b-256 f532ebdf4828b76e863b3b968d10b6ba03444e15cc7af94798ed06e05b1922dc

See more details on using hashes here.

Provenance

The following attestation bundles were made for pypersistent-2.0.0b1-cp311-cp311-macosx_10_9_x86_64.whl:

Publisher: build-wheels.yml on cmarschner/pypersistent

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file pypersistent-2.0.0b1-cp310-cp310-win_amd64.whl.

File metadata

File hashes

Hashes for pypersistent-2.0.0b1-cp310-cp310-win_amd64.whl
Algorithm Hash digest
SHA256 81cb98c658687a2fdbe473ab93c3a07dd56fab10718dd22c396b5ac3ee1d5c7b
MD5 ed34c351a1d79cf26e76844bb71e0db9
BLAKE2b-256 a3920d0c061c92c3de73f212e25addbabbffc45c57faf38863f43ec42018dd73

See more details on using hashes here.

Provenance

The following attestation bundles were made for pypersistent-2.0.0b1-cp310-cp310-win_amd64.whl:

Publisher: build-wheels.yml on cmarschner/pypersistent

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file pypersistent-2.0.0b1-cp310-cp310-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl.

File metadata

File hashes

Hashes for pypersistent-2.0.0b1-cp310-cp310-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl
Algorithm Hash digest
SHA256 0d5cab8a03f634cc24ebffae2f25f430fbff5dd3d2a3e6623a2100e525f01f9f
MD5 f9cd119ace1601336703351f0f8c2cbf
BLAKE2b-256 2c5e5101c7f16d64e852036e3a367890e2b50d87440e505fbc20d80e778793c6

See more details on using hashes here.

Provenance

The following attestation bundles were made for pypersistent-2.0.0b1-cp310-cp310-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl:

Publisher: build-wheels.yml on cmarschner/pypersistent

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file pypersistent-2.0.0b1-cp310-cp310-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl.

File metadata

File hashes

Hashes for pypersistent-2.0.0b1-cp310-cp310-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl
Algorithm Hash digest
SHA256 32c7c6e5074e44b894d05d568e17186ddc3cce54a092196f3d8572e009a6753a
MD5 dd7a58cd6128cd230dae88f6d4ea78b9
BLAKE2b-256 1fe3b509388b39269e87a3dd82cedb62a9c6dff063d6f0461b17b089fdd9b220

See more details on using hashes here.

Provenance

The following attestation bundles were made for pypersistent-2.0.0b1-cp310-cp310-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl:

Publisher: build-wheels.yml on cmarschner/pypersistent

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file pypersistent-2.0.0b1-cp310-cp310-macosx_11_0_arm64.whl.

File metadata

File hashes

Hashes for pypersistent-2.0.0b1-cp310-cp310-macosx_11_0_arm64.whl
Algorithm Hash digest
SHA256 4d0a744d22dcdee9a023f8eaccb7a7cdacbff5baa1008962ea705da0d8755c26
MD5 a80be17f0a0b80e6ed3330578bc03ae2
BLAKE2b-256 1afc32f9a1df6e7c5e2020e5c519c0b0309fc569f89d692b31b1551e1fb83ec9

See more details on using hashes here.

Provenance

The following attestation bundles were made for pypersistent-2.0.0b1-cp310-cp310-macosx_11_0_arm64.whl:

Publisher: build-wheels.yml on cmarschner/pypersistent

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file pypersistent-2.0.0b1-cp310-cp310-macosx_10_9_x86_64.whl.

File metadata

File hashes

Hashes for pypersistent-2.0.0b1-cp310-cp310-macosx_10_9_x86_64.whl
Algorithm Hash digest
SHA256 c47d22bd79c73e8dae2b311ea341ce23249397978936a8fa899f5d9a0b09617b
MD5 6828c7eb35da9b78d315b2ee863906f8
BLAKE2b-256 4246d4558a667ee15a1f31f07f5a9a89312d3520f9523af5dc8ebc0982b77fea

See more details on using hashes here.

Provenance

The following attestation bundles were made for pypersistent-2.0.0b1-cp310-cp310-macosx_10_9_x86_64.whl:

Publisher: build-wheels.yml on cmarschner/pypersistent

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

Supported by

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