Registry / serialization / pyrsistent

pyrsistent

JSON →
library0.20.0pypypi✓ verified 28d ago

Pyrsistent is a Python library providing persistent and immutable data structures, such as lists, dictionaries, and sets, that facilitate functional programming paradigms. Unlike mutable data structures, all operations that would typically modify a `pyrsistent` object instead return a new, updated copy, leaving the original untouched. This simplifies reasoning about program state by eliminating hidden side effects. The library is currently at version 0.20.0, released in October 2023, and is actively maintained.

pip install pyrsistent
INSTALL
IMPORT
SIG · PYRSISTENT
P
pyrsistent
serializationpythonv0.20.0
Install
1.8s avg
Import
49ms
Disk
16MB
Pass rate
10/ 10
Env Coverage10 / 10
glibc
3.9–3.13
musl
3.9–3.13
Install & Compatibility
Where this runs
tested against v0.20.0 · pip install
no network on importno background threads
Install × environment matrix
Each cell = how many times install + import succeeded across repeated harness runs. Partial = flaky.
glibc = Debian/Ubuntu slim · musl = Alpine Linux
musl
py 3.10–3.95 runs
installs and imports cleanly · install 0.0s · import 0.048s · 18.2MB
glibc
py 3.10–3.95 runs
installs and imports cleanly · install 1.8s · import 0.050s · 19MB
16MB installed
● package 16MB
Code
Verified usage

Verified import paths — ran on the pinned version, not inferred.

PVector
✓ from pyrsistent import PVector
For persistent lists; also commonly imported via the 'v' factory function: `from pyrsistent import v`
PMap
✓ from pyrsistent import PMap
For persistent dictionaries; also commonly imported via the 'm' factory function: `from pyrsistent import m`
PSet
✓ from pyrsistent import PSet
For persistent sets; also commonly imported via the 's' factory function: `from pyrsistent import s`
PRecord
✓ from pyrsistent import PRecord
For immutable objects with fixed fields, similar to named tuples but with PMap capabilities.
freeze
✓ from pyrsistent import freeze
Recursively converts mutable Python collections to their pyrsistent counterparts.
thaw
✓ from pyrsistent import thaw
Recursively converts pyrsistent collections back to mutable Python collections.

This quickstart demonstrates the creation and immutable 'evolution' of `PVector` (list-like), `PMap` (dict-like), and `PRecord` (object-like) instances. Operations like `append`, `set`, or `discard` always return a new instance with the changes, ensuring the original data structure's integrity.

from pyrsistent import pvector, pmap, PRecord # Create a persistent vector (list-like) v1 = pvector([1, 2, 3]) v2 = v1.append(4) # Returns a new pvector, v1 remains unchanged v3 = v2.set(1, 5) # Replaces element at index 1 print(f"Original vector: {v1}") # Expected: pvector([1, 2, 3]) print(f"Appended vector: {v2}") # Expected: pvector([1, 2, 3, 4]) print(f"Modified vector: {v3}") # Expected: pvector([1, 5, 3, 4]) # Create a persistent map (dict-like) m1 = pmap({'a': 1, 'b': 2}) m2 = m1.set('c', 3) # Returns a new pmap, m1 remains unchanged m3 = m2.set('a', 5) # Updates value for key 'a' print(f"Original map: {m1}") # Expected: pmap({'a': 1, 'b': 2}) print(f"Appended map: {m2}") # Expected: pmap({'a': 1, 'b': 2, 'c': 3}) print(f"Modified map: {m3}") # Expected: pmap({'a': 5, 'b': 2, 'c': 3}) # Define a persistent record class User(PRecord): name = None age = None user1 = User(name='Alice', age=30) user2 = user1.set(age=31) # Returns a new User record print(f"Original user: {user1}") # Expected: User(name='Alice', age=30) print(f"Updated user: {user2}") # Expected: User(name='Alice', age=31)
Debug
Known issues
breakingThe behavior of `freeze` and `thaw` functions changed in a past update (related to issue #209). They now recursively convert `pyrsistent` data structures into Python built-in types and vice-versa. To retain the *old* (less recursive) behavior, you must explicitly pass `strict=False`.
fix
Review calls to `freeze()` and `thaw()`. If deep recursion is undesired, pass `strict=False` (e.g., `freeze(my_pyrsistent_obj, strict=False)`).
affects: <=0.20.0 (change was introduced prior to 0.20.0, affects users migrating from older versions)
breakingThe behavior of `PMap.remove()` was changed in version 0.7.0. It now raises a `KeyError` if the element to be removed is not present. The `PMap.discard()` method was introduced as an alternative that returns the original `PMap` instance if the element is not found, aligning with `PSet`'s behavior.
fix
Replace `PMap.remove(key)` with `PMap.discard(key)` if you want to avoid `KeyError` when a key might not exist, or ensure you handle the `KeyError` if `remove` is used.
affects: >=0.7.0
breakingThe methods `PMap.merge()` and `PMap.merge_with()` were deprecated and subsequently removed. They were renamed to `PMap.update()` and `PMap.update_with()` respectively.
fix
Replace calls to `merge()` with `update()` and `merge_with()` with `update_with()`.
affects: <1.0 (deprecated before 0.6.3, removed by 1.0)
gotchaPyrsistent data structures are fundamentally immutable. Any method that appears to 'modify' a structure (e.g., `append`, `set`, `remove`) actually returns a *new* instance with the changes, leaving the original unchanged. Attempting to treat them as mutable will lead to unexpected results where the original object appears not to have changed.
fix
Always assign the result of modification operations to a new variable or back to the original variable to capture the new state (e.g., `my_vec = my_vec.append(item)`). Understand that you are always creating new versions, not altering existing ones.
affects: All versions
gotchaFor scenarios requiring many sequential updates to a `pyrsistent` collection where intermediate states are not needed, using an 'Evolver' (`pvector.evolver()`, `pmap.evolver()`, `pset.evolver()`) can be more efficient. Evolvers provide a mutable view for temporary, batch updates before finalizing to a new persistent structure.
fix
Wrap sequences of temporary mutations in an evolver: `with my_pvector.evolver() as e: e[idx] = val; e.append(item); new_pvector = e.persistent()`.
affects: All versions
gotchaPRecords require fields to be explicitly defined as part of their class definition. Attempting to initialize or set a field that was not declared will raise an `AttributeError`.
fix
Ensure all fields you intend to use with a `PRecord` are explicitly declared in its class definition using `field()` or `_fields`. For example: `class MyRecord(PRecord): name = field(); age = field()`.
affects: All versions
breakingPRecord instances must be initialized only with fields explicitly defined using `PRecord.field()` in the subclass. Passing keyword arguments for fields not declared in the `PRecord` definition will raise an `AttributeError`.
fix
Ensure that all fields intended to be set during `PRecord` instantiation are explicitly declared in the `PRecord` subclass using `PRecord.field()`. Alternatively, review the instantiation call to only pass declared fields.
affects: All versions
Errors
Common errors & fixes
TypeError: 'pvector' object does not support item assignment
Users attempt to modify a `pvector` in-place using item assignment (`pv[idx] = value`), which is not allowed because `pvector` is an immutable data structure.
fix
Use the `set` method, which returns a new `pvector` with the updated value at the specified index. Example: `new_pv = pv.set(1, 10)`
TypeError: 'pmap' object does not support item assignment
Users attempt to modify a `pmap` in-place using item assignment (`pm[key] = value`), which is not allowed because `pmap` is an immutable data structure.
fix
Use the `set` method, which returns a new `pmap` with the updated value for the specified key. Example: `new_pm = pm.set('b', 20)`
AttributeError: 'pvector' object has no attribute 'append'
Users try to use mutable list methods like `append` in-place on a `pvector` object, which is immutable and returns new instances on modification.
fix
Use the `append` method of `pvector`, which returns a new `pvector` with the added element. Example: `new_pv = pv.append(3)`
TypeError: 'pset' object is not subscriptable
Users attempt to access elements of a `pset` using indexing (`ps[index]`), which is not supported as sets are unordered and do not allow indexed access.
fix
To check for membership, use the `in` operator (e.g., `if value in ps:`). If indexed access is required, convert the `pset` to a list first (e.g., `list(ps)[0]`).
Upgrade
Version history
0.20.0latest on PyPI · released Oct 25, 2023
Audit
Dependencies

No dependency data recorded yet.

Agent activity
16 hits · last 30 days
node
14
Resources