Skip to main content

Imperative modifications of immutable collections

Overview

The pyrsistent-mutable package presents a decorator that will transform a decorated function to use the pyrsistent API.

This means that a set of specific operations are transformed:

  • Construction of literal sets, dicts and lists are transformed into calls to pset, pvector and pmap.

  • Assignments are rewritten to handle:
    • Assignments to attributes become evolve calls; nesting is handled correctly.

    • Augmented assignments are transformed into regular assignments.

  • Standalone method invocations are transformed into assignments.

from pyrsistent_mutable import pyrmute
from pyrsistent import PRecord, field

class Simple(PRecord):
    attr = field()
    other = field()

@pyrmute
def example_func():
    # Built in referential integrity
    save_vector = my_vector = [0, 1, 2, 3, 4]  # Mapped to a pvector
    del my_vector[3]  # Does *not* change save_vector

    # Evolve nested attributes
    my_precord = Simple(attr=Simple(), other=[])
    my_precord.attr.attr = 5
    my_precord.other.append(20)

    # Transforms literals and comprehensions
    my_maps = [{'filling': key} for key in ('apple', 'banana')]
    my_maps[0]['crust'] = 'flaky'

    return my_vector, save_vector, my_precord, my_maps

This example is tested in tests/test_readme.py.

What’s the point?

It’s entirely that the imperative form is easier to read, and that pyrsistent’s API is tedious for nested collections, at least compared to native Python syntax.

Also, I’m working on a language that uses this technique more extensively, so this was an opportunity to turn a prototype into something more generally useful.

Installing

Installation should just be:

# Install via pip, preferred.
pip3 install pyrsistent-mutable

# Install traditionally.
python3 setup.py install

Usage

Beyond the example shown above, the main things to keep in mind when using this module:

  • You function still needs to return values.

  • A “copy” can be made by simple assignment.

  • Lists, dicts and sets literals and comprehensions are transformed.

  • Tuples are not transformed, nor are generators.

  • Method calls are only transformed if they are standalone expressions.

  • Rewritten operations should fall back to normal behavior for non-pyrsistent values.

  • The decorated function can’t allow nonlocal names.

  • global may not work.

Troubleshooting

This is really just trying to take a prototype and do something useful with it.

If a function isn’t calling something in a useful manner, the culprit is probably my very lame implementations in pyrsistent_mutable.globals.

Don’t forget to return

This only munges assignments and expression statements.

Read the __source__

The transformed code is written into your function under __source__ which may be helpful in debugging.

Known limits

Most of these are because I’ve only done very preliminary work to map imperative operations to pyrsistent values.

  • Assignment of slices uses the evolver framework, which doesn’t handle complex slices.

  • Deletion of slices similarly doesn’t work.

  • Augmented assignment generally requires a pyrsistent value on the rhs.
    • This is mitigated now that the module translates literals.

  • It is not tested on asynchronous functions or generators. It shouldn’t care about them, though.

  • It’s all or nothing.

  • The top level function can’t have nonlocal names. Embedded functions can, though.

Debugging

By default, the decorator will write the transformed source to your function as __source__. I just pulled that name out my hat. You can call the decorator with write_source=False to disable this.

Package maintainer notes

pip install twine
python setup.py bdist_wheel
twine upload dist/pyrsistent_mutable-0.0.x-py3-none-any.whl

Metadata

Release files for pyrsistent-mutable 0.0.6

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Built distributions (wheels)

Table of built distributions (wheels) for pyrsistent-mutable 0.0.6
File Interpreter ABI Platform
pyrsistent_mutable-0.0.6-py3-none-any.whl Python 3 none any Details
pyrsistent_mutable-0.0.6-py2-none-any.whl Python 2 none any Details

Total release size: 27.9 kB

Release files / pyrsistent_mutable-0.0.6-py3-none-any.whl

Download URL pyrsistent_mutable-0.0.6-py3-none-any.whl
Size 13.9 kB
Tags Python 3
SHA-256 checksum
How to use checksums
5426d8e1a68101c814c9e270b4b6870f4180aeb141aeefe26f39f66e44846dbf
BLAKE2b-256 checksum
How to use checksums
6250845e7c980521eef391ddb8720c69b80ebadc8a0826baa323e8e743be28de
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No

Release files / pyrsistent_mutable-0.0.6-py2-none-any.whl

Download URL pyrsistent_mutable-0.0.6-py2-none-any.whl
Size 14.0 kB
Tags Python 2
SHA-256 checksum
How to use checksums
1434aaa3a01a2fabb27d436d1100dfaa8ff12ee8207077582352023c41cd5667
BLAKE2b-256 checksum
How to use checksums
1a68f316bf5063b3cc74c74101a3ec943f91d2c79e9b8924275ef0f9098ea295
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No

Release history Release notifications | RSS feed

This release

0.0.6 This release

2 release files

0.0.5

1 release file

0.0.4

1 release file

0.0.3

1 release file

0.0.1

1 release file

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page