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 maps, leaving originals unchanged
  • Structural Sharing: New versions share most structure with old versions (O(log n) copies instead of O(n))
  • Fast: 38% faster than pure Python implementation for insertions, ~10x slower than mutable dict
  • 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:

PersistentMap

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 PersistentMap
    
    m = PersistentMap.create(name='Alice', age=30)
    m2 = m.set('city', 'NYC')
    m3 = m | {'role': 'developer'}  # Merge
    

PersistentTreeMap

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 PersistentTreeMap
    
    m = PersistentTreeMap.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')
    

PersistentVector

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 PersistentVector
    
    v = PersistentVector.create(1, 2, 3)
    v2 = v.conj(4)  # Append
    v3 = v2.assoc(0, 10)  # Update index 0
    v[1]  # 2 - indexed access
    

PersistentHashSet

Unordered set based on HAMT (same as PersistentMap).

  • 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 PersistentHashSet
    
    s = PersistentHashSet.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; PersistentMap automatically uses this for small maps

Choosing the Right Data Structure

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

Performance

Quick Summary

pypersistent provides 6-8% faster bulk operations compared to baseline and is 3-150x faster than pure Python pyrsistent for most operations. The real value is structural sharing: creating variants is 3000x faster than copying dicts.

Benchmark Results

vs Python dict (1M elements)

Operation pypersistent dict Notes
Construction 2.74s 299ms 9x slower (immutability cost)
Lookup (1K ops) 776ms 427ms 1.8x slower
Update (single) 147µs ~80ns Comparable for single ops
Structural Sharing (100 variants) 0.48ms 1.57s 3000x FASTER

Key insight: For creating multiple versions, pypersistent is orders of magnitude faster.

vs pyrsistent (pure Python) - Apples-to-Apples

Size Operation pypersistent pyrsistent Speedup
1M Merge (500K+500K) 11.5ms 1.60s 139x faster
1M Construction 185ms 813ms 4.4x faster
1M Lookup (1M ops) 726ms 796ms 1.1x faster
1M Iteration 452ms 167ms 2.7x slower
1K Merge (500+500) 8.7µs 1.22ms 141x faster
1K Construction 76µs 192µs 2.5x faster
100 Merge (50+50) 17.8µs 120µs 6.7x faster
100 Construction 30µs 18.5µs 1.6x slower

Iteration note: Using items_list() instead of items() makes iteration 1.7-3x faster for maps < 100K

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 maps, use materialized list methods:

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

# Fast methods (1.7-3x faster for maps < 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 maps or early exit)
for k, v in m.items():   # Generator, O(log n) memory
    ...

Performance:

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

When to Use pypersistent

Use pypersistent when:

  • Creating multiple versions of data (undo/redo, time-travel)
  • Concurrent access across threads (lock-free reads)
  • Functional programming patterns
  • Merging large maps frequently

Use dict when:

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

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

Usage

PersistentMap - Hash Map

from pypersistent import PersistentMap

# Create
m = PersistentMap.create(name='Alice', age=30)
m = PersistentMap.from_dict({'name': 'Alice', 'age': 30})

# Add/update (functional style)
m2 = m.assoc('city', 'NYC')

# Add/update (Pythonic style)
m2 = m.set('city', 'NYC')
m3 = m | {'role': 'developer'}  # Merge

# Get
name = m['name']  # Raises KeyError if missing
name = m.get('name', 'default')

# Remove
m4 = m.dissoc('age')  # Functional
m4 = m.delete('age')  # Pythonic

# Check membership
'name' in m  # True

# Iterate
for key, value in m.items():
    print(key, value)

PersistentTreeMap - Sorted Map

from pypersistent import PersistentTreeMap

# Create (automatically sorted by keys)
m = PersistentTreeMap.from_dict({3: 'c', 1: 'a', 2: 'b'})
list(m.keys())  # [1, 2, 3]

# Same API as PersistentMap
m2 = m.assoc(4, 'd')
m3 = m.dissoc(1)

# Sorted-specific operations
first_entry = m.first()  # (1, 'a')
last_entry = m.last()    # (3, 'c')

# Range queries
sub = m.subseq(start=1, end=3)  # Keys 1-2 (end exclusive)
list(sub.keys())  # [1, 2]

rsub = m.rsubseq(start=3, end=1)  # Reverse order
list(rsub.keys())  # [3, 2]

PersistentVector - Indexed Sequence

from pypersistent import PersistentVector

# Create
v = PersistentVector.create(1, 2, 3)
v = PersistentVector.from_list([1, 2, 3])

# Append (functional)
v2 = v.conj(4)  # [1, 2, 3, 4]

# Update by index
v3 = v.assoc(0, 10)  # [10, 2, 3]

# Access by index
first = v[0]  # 1
last = v[-1]  # 3

# Slice
sub = v[1:3]  # PersistentVector([2, 3])

# Iterate
for item in v:
    print(item)

# Length
len(v)  # 3

PersistentHashSet - Set

from pypersistent import PersistentHashSet

# Create
s = PersistentHashSet.create(1, 2, 3)
s = PersistentHashSet.from_set({1, 2, 3})

# Add
s2 = s.conj(4)  # {1, 2, 3, 4}

# Remove
s3 = s.disj(2)  # {1, 3}

# Membership
2 in s  # True

# Set operations
s1 = PersistentHashSet.create(1, 2, 3)
s2 = PersistentHashSet.create(3, 4, 5)

union = s1 | s2  # {1, 2, 3, 4, 5}
intersection = s1 & s2  # {3}
difference = s1 - s2  # {1, 2}

# Iterate
for item in s:
    print(item)

API Summary

Common operations (all data structures):

  • create(*args) - Create from elements
  • from_X(...) - Create from Python collection
  • Immutability - all operations return new instances
  • Thread-safe reads - safe to share across threads

PersistentMap / PersistentTreeMap:

  • assoc(k, v) / set(k, v) - Add/update
  • dissoc(k) / delete(k) - Remove
  • get(k, default=None) - Get value
  • m[k] - Get (raises KeyError)
  • k in m - Membership
  • keys(), values(), items() - Iterators
  • m1 | m2 - Merge

PersistentTreeMap only:

  • first() - Min entry
  • last() - Max entry
  • subseq(start, end) - Range query
  • rsubseq(start, end) - Reverse range

PersistentVector:

  • conj(item) - Append
  • assoc(idx, val) - Update by index
  • v[idx] - Get by index
  • v[start:end] - Slice
  • len(v) - Length

PersistentHashSet:

  • conj(item) - Add
  • disj(item) - Remove
  • item in s - Membership
  • s1 | s2 - Union
  • s1 & s2 - Intersection
  • s1 - s2 - Difference

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:

PersistentMap - 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

PersistentTreeMap - 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

PersistentVector - 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

PersistentHashSet - HAMT-based Set

Uses PersistentMap internally with:

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

PersistentArrayMap - Simple Array

Linear array for tiny maps (< 8 entries):

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

Technical Details

Complexity:

  • PersistentMap/HashSet: O(log₃₂ n) ≈ 6 steps for 1M elements
  • PersistentTreeMap: O(log₂ n) for all operations
  • PersistentVector: 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 PersistentMap

# Shared base map
base_config = PersistentMap.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_map.py -v
pytest test_persistent_tree_map.py -v
pytest test_persistent_vector.py -v
pytest test_persistent_hash_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.0a1.tar.gz (52.0 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.0a1-cp312-cp312-win_amd64.whl (173.8 kB view details)

Uploaded CPython 3.12Windows x86-64

pypersistent-2.0.0a1-cp312-cp312-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl (270.3 kB view details)

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

pypersistent-2.0.0a1-cp312-cp312-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl (252.6 kB view details)

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

pypersistent-2.0.0a1-cp312-cp312-macosx_11_0_arm64.whl (238.2 kB view details)

Uploaded CPython 3.12macOS 11.0+ ARM64

pypersistent-2.0.0a1-cp312-cp312-macosx_10_9_x86_64.whl (246.4 kB view details)

Uploaded CPython 3.12macOS 10.9+ x86-64

pypersistent-2.0.0a1-cp311-cp311-win_amd64.whl (174.2 kB view details)

Uploaded CPython 3.11Windows x86-64

pypersistent-2.0.0a1-cp311-cp311-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl (273.4 kB view details)

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

pypersistent-2.0.0a1-cp311-cp311-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl (255.9 kB view details)

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

pypersistent-2.0.0a1-cp311-cp311-macosx_11_0_arm64.whl (236.4 kB view details)

Uploaded CPython 3.11macOS 11.0+ ARM64

pypersistent-2.0.0a1-cp311-cp311-macosx_10_9_x86_64.whl (240.6 kB view details)

Uploaded CPython 3.11macOS 10.9+ x86-64

pypersistent-2.0.0a1-cp310-cp310-win_amd64.whl (173.4 kB view details)

Uploaded CPython 3.10Windows x86-64

pypersistent-2.0.0a1-cp310-cp310-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl (269.8 kB view details)

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

pypersistent-2.0.0a1-cp310-cp310-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl (252.7 kB view details)

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

pypersistent-2.0.0a1-cp310-cp310-macosx_11_0_arm64.whl (234.5 kB view details)

Uploaded CPython 3.10macOS 11.0+ ARM64

pypersistent-2.0.0a1-cp310-cp310-macosx_10_9_x86_64.whl (238.3 kB view details)

Uploaded CPython 3.10macOS 10.9+ x86-64

File details

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

File metadata

  • Download URL: pypersistent-2.0.0a1.tar.gz
  • Upload date:
  • Size: 52.0 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.0a1.tar.gz
Algorithm Hash digest
SHA256 a92fff0221915ef4c9e6a5e804a274cb57e9434eec75fd7ce07ff32577b7af65
MD5 d61b1180fe0f2335773c9ff45ecd1a9a
BLAKE2b-256 1f4bf873d869d4ea99d4eb7887dc307d886a93d432faadd42eddf498da8f456a

See more details on using hashes here.

Provenance

The following attestation bundles were made for pypersistent-2.0.0a1.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.0a1-cp312-cp312-win_amd64.whl.

File metadata

File hashes

Hashes for pypersistent-2.0.0a1-cp312-cp312-win_amd64.whl
Algorithm Hash digest
SHA256 a9ba6446baf1be5c01e2d79e211ea64e6967eb7b7022279c9ea85aa78e5f85de
MD5 de0ced0be90a9b8e71561cb29644f134
BLAKE2b-256 1c804c62417e53eaca7e9bda653dffc741a264def09a1813297adb87dc54ae3d

See more details on using hashes here.

Provenance

The following attestation bundles were made for pypersistent-2.0.0a1-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.0a1-cp312-cp312-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl.

File metadata

File hashes

Hashes for pypersistent-2.0.0a1-cp312-cp312-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl
Algorithm Hash digest
SHA256 ff18a74753671354e69da81f24a85c79b5b5b961defb8e970ad1a072e72ee180
MD5 a3e3b9a97dae21fd2df5114bd24969fc
BLAKE2b-256 f907534a29844724c9ac88b8682c265eb8219da2eac4b51256e9c99cf3218d44

See more details on using hashes here.

Provenance

The following attestation bundles were made for pypersistent-2.0.0a1-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.0a1-cp312-cp312-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl.

File metadata

File hashes

Hashes for pypersistent-2.0.0a1-cp312-cp312-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl
Algorithm Hash digest
SHA256 d332d900c3bd43ee7e3894f720d6007ef9a9141fa7d63c999da4f013640478c1
MD5 e725985b94ac0316d11f24ddf9c76f5d
BLAKE2b-256 a925071fa41443c8af83744b12a3c5554043a5fbd912a1cd5dea9a223dbab9b8

See more details on using hashes here.

Provenance

The following attestation bundles were made for pypersistent-2.0.0a1-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.0a1-cp312-cp312-macosx_11_0_arm64.whl.

File metadata

File hashes

Hashes for pypersistent-2.0.0a1-cp312-cp312-macosx_11_0_arm64.whl
Algorithm Hash digest
SHA256 7d2159ab64f3715c433ffb9e671104c0ce53fe1863005fc6429fec34ad999983
MD5 fc126fd06a7eb0583f59488e9b6aec0f
BLAKE2b-256 aac367dbf7e35a27e25a5a14acc9bcf558feb0e84ff8183141414c0be13e61d0

See more details on using hashes here.

Provenance

The following attestation bundles were made for pypersistent-2.0.0a1-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.0a1-cp312-cp312-macosx_10_9_x86_64.whl.

File metadata

File hashes

Hashes for pypersistent-2.0.0a1-cp312-cp312-macosx_10_9_x86_64.whl
Algorithm Hash digest
SHA256 dd23eef4ea797d9ad99968d8b8cabd1e8af5d2607fc44f6526f95706fce412c1
MD5 e6d6d8aaf8ba89b954461a385887ba95
BLAKE2b-256 33a927b8bfff1ac544ff9eb90e0000f0b66e762f44ea67fb4db581e6b6a7c303

See more details on using hashes here.

Provenance

The following attestation bundles were made for pypersistent-2.0.0a1-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.0a1-cp311-cp311-win_amd64.whl.

File metadata

File hashes

Hashes for pypersistent-2.0.0a1-cp311-cp311-win_amd64.whl
Algorithm Hash digest
SHA256 841a8d2b9336d0ed6dc924001c9074161b4095a92b268da98e4686826847b043
MD5 1e0f5338209a7c557995e1f35dca1a83
BLAKE2b-256 67344c312df67db88800dcc20a78aff01fa3b1d21f6194a5381c6a71e9728b80

See more details on using hashes here.

Provenance

The following attestation bundles were made for pypersistent-2.0.0a1-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.0a1-cp311-cp311-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl.

File metadata

File hashes

Hashes for pypersistent-2.0.0a1-cp311-cp311-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl
Algorithm Hash digest
SHA256 969880c8a5f5f33914e38016b51f6c4d1ac94d3b01e888731dc3c44822dacfb0
MD5 d6b93bc7df85f6e41e2b83209b7fa966
BLAKE2b-256 f339da98ab73c6d208b8155263e340c5041b49dc81e456d1a778fe094d6909cb

See more details on using hashes here.

Provenance

The following attestation bundles were made for pypersistent-2.0.0a1-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.0a1-cp311-cp311-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl.

File metadata

File hashes

Hashes for pypersistent-2.0.0a1-cp311-cp311-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl
Algorithm Hash digest
SHA256 9c06b96254b386a00e4977fcc455f950922b5885365d30ade83d1c36ec1fcf4a
MD5 56ec4cb2d68c0bd3d18f823d5bd86654
BLAKE2b-256 7991f83a630f6971ad4189058cbd9204634902e97af3e51b9ca17ca08eaa73fb

See more details on using hashes here.

Provenance

The following attestation bundles were made for pypersistent-2.0.0a1-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.0a1-cp311-cp311-macosx_11_0_arm64.whl.

File metadata

File hashes

Hashes for pypersistent-2.0.0a1-cp311-cp311-macosx_11_0_arm64.whl
Algorithm Hash digest
SHA256 21e3be673ce8f07cf89dadb8e6cac48b0e012f6cf74102e4b4b877f039fd45b0
MD5 4f04d7c94c8939add02775bef8c83975
BLAKE2b-256 2c06f883622a1aff5b50caf559fe0f9309a1079c9e6712886790bed383e2d0c5

See more details on using hashes here.

Provenance

The following attestation bundles were made for pypersistent-2.0.0a1-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.0a1-cp311-cp311-macosx_10_9_x86_64.whl.

File metadata

File hashes

Hashes for pypersistent-2.0.0a1-cp311-cp311-macosx_10_9_x86_64.whl
Algorithm Hash digest
SHA256 218390fbbcd0258bee8c2abea40076691d4e8b911c52cc396bf4eba82cc51e5c
MD5 493ce0b83d2afa1e3ee1da4033b6b559
BLAKE2b-256 59e2b9e1ff401e7ddb8b51d5e46c5e89e0d3e91b63629f96fd91c0cfd7d7c5a6

See more details on using hashes here.

Provenance

The following attestation bundles were made for pypersistent-2.0.0a1-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.0a1-cp310-cp310-win_amd64.whl.

File metadata

File hashes

Hashes for pypersistent-2.0.0a1-cp310-cp310-win_amd64.whl
Algorithm Hash digest
SHA256 ea018a11bf4cd733001aaff6343cc8aba74fed0c608a6086934976a0833b8b6a
MD5 122ab6561fee254c6b0fe281059a5b65
BLAKE2b-256 35ee94a47b5024da856209df91b554633b5788a783d52ece547437a061e54a45

See more details on using hashes here.

Provenance

The following attestation bundles were made for pypersistent-2.0.0a1-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.0a1-cp310-cp310-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl.

File metadata

File hashes

Hashes for pypersistent-2.0.0a1-cp310-cp310-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl
Algorithm Hash digest
SHA256 9dde4d10f46c2c548ceb2d29d371b10ce95ee5be6dfa8afced6cfa060130a8a2
MD5 b630764fd75f9e47fd2d8e7efd023a36
BLAKE2b-256 b670e0e46a98eba0617f6bd11328ed76cd3094c7ff8c38530fda2353f3ad2f6a

See more details on using hashes here.

Provenance

The following attestation bundles were made for pypersistent-2.0.0a1-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.0a1-cp310-cp310-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl.

File metadata

File hashes

Hashes for pypersistent-2.0.0a1-cp310-cp310-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl
Algorithm Hash digest
SHA256 d35c8fc5af407ae0fea0cc0873ba7820e2d94cae2377efbcd64ad31090688af5
MD5 82db4cee37f2248ff48d34b0c0acf373
BLAKE2b-256 145173669d1f14927691c5af9ceb90ddd6a10dcd7a2d3d91a3c8b31cdab75e20

See more details on using hashes here.

Provenance

The following attestation bundles were made for pypersistent-2.0.0a1-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.0a1-cp310-cp310-macosx_11_0_arm64.whl.

File metadata

File hashes

Hashes for pypersistent-2.0.0a1-cp310-cp310-macosx_11_0_arm64.whl
Algorithm Hash digest
SHA256 f25fc6f7ea2138d2ba46287d8b04ba8279532fff9263e61c02498e823800cbd4
MD5 0bf043d85536c8e1661d9d78d9b10f5f
BLAKE2b-256 975d4a3a39c5c9d47445797247ab4add56434215aed9af15de56c850b82c76c9

See more details on using hashes here.

Provenance

The following attestation bundles were made for pypersistent-2.0.0a1-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.0a1-cp310-cp310-macosx_10_9_x86_64.whl.

File metadata

File hashes

Hashes for pypersistent-2.0.0a1-cp310-cp310-macosx_10_9_x86_64.whl
Algorithm Hash digest
SHA256 ee4ff12f4ce14b566743c60babee81f17c1ee3b3568d35a831f2a705e41d2745
MD5 0be4d985a3ceb211819475405b96b9cf
BLAKE2b-256 0d6cec2f05261d32668bed5d29a4a3e45b0d0c30aef348a04241d4bf128842a9

See more details on using hashes here.

Provenance

The following attestation bundles were made for pypersistent-2.0.0a1-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