### Running Tests with Tox Source: https://github.com/tobgu/pyrsistent/blob/master/docs/source/intro.rst Instructions for installing and running tests using the tox tool. Tox is used to automate testing in different Python environments. ```Shell pip install tox ``` ```Shell tox -e py38 ``` -------------------------------- ### Running Tests with Tox Source: https://github.com/tobgu/pyrsistent/blob/master/README.rst Instructions for installing and running tests using the tox tool. Tox is used to automate testing in different Python environments. ```Shell pip install tox ``` ```Shell tox -e py38 ``` -------------------------------- ### Invariant Exception Handling Example Source: https://github.com/tobgu/pyrsistent/blob/master/docs/source/intro.rst Provides an example of how invariant violations are caught and reported. It shows a try-except block catching an InvariantException and printing the specific invariant errors associated with the failed operation. ```python from pyrsistent import InvariantException >>> try: ... EvenX(x=-1) ... except InvariantException as e: ... print(e.invariant_errors) ... (('x negative', 'x odd'),) ``` -------------------------------- ### Release Process Commands Source: https://github.com/tobgu/pyrsistent/blob/master/docs/source/intro.rst Steps involved in releasing a new version of Pyrsistent. This includes installing dependencies, updating version files, committing changes, tagging, and pushing. ```Shell pip install -r requirements.txt ``` ```Shell git add -u . git commit -m 'Prepare version vX.Y.Z' git tag -a vX.Y.Z -m 'vX.Y.Z' ``` ```Shell git push --follow-tags ``` -------------------------------- ### Release Process Commands Source: https://github.com/tobgu/pyrsistent/blob/master/README.rst Steps involved in releasing a new version of Pyrsistent. This includes installing dependencies, updating version files, committing changes, tagging, and pushing. ```Shell pip install -r requirements.txt ``` ```Shell git add -u . git commit -m 'Prepare version vX.Y.Z' git tag -a vX.Y.Z -m 'vX.Y.Z' ``` ```Shell git push --follow-tags ``` -------------------------------- ### Invariant Exception Handling Example Source: https://github.com/tobgu/pyrsistent/blob/master/README.rst Provides an example of how invariant violations are caught and reported. It shows a try-except block catching an InvariantException and printing the specific invariant errors associated with the failed operation. ```python from pyrsistent import InvariantException >>> try: ... EvenX(x=-1) ... except InvariantException as e: ... print(e.invariant_errors) ... (('x negative', 'x odd'),) ``` -------------------------------- ### Freeze and Thaw Example Source: https://github.com/tobgu/pyrsistent/blob/master/README.rst Demonstrates the use of `freeze` and `thaw` functions to convert between mutable and immutable data structures. `freeze` converts Python lists and dicts into pyrsistent's PVector and PMap, respectively. `thaw` performs the inverse operation. ```python from pyrsistent import freeze, thaw, v, m freeze([1, {'a': 3}]) thaw(v(1, m(a=3))) ``` -------------------------------- ### Freeze and Thaw Example Source: https://github.com/tobgu/pyrsistent/blob/master/docs/source/intro.rst Demonstrates the use of `freeze` and `thaw` functions to convert between mutable and immutable data structures. `freeze` converts Python lists and dicts into pyrsistent's PVector and PMap, respectively. `thaw` performs the inverse operation. ```python from pyrsistent import freeze, thaw, v, m freeze([1, {'a': 3}]) thaw(v(1, m(a=3))) ``` -------------------------------- ### Python pyrsistent Transformations Source: https://github.com/tobgu/pyrsistent/blob/master/docs/source/intro.rst Demonstrates the use of the `transform` method on pyrsistent data structures (PMaps, PVectors) to modify values at specified paths. Supports index-based paths, callable matchers, regular expressions, and the `ny` (any) matcher for flexible data manipulation. Includes examples of deep transformations and discarding elements. ```python from pyrsistent import inc, freeze, thaw, rex, ny, discard v1 = freeze([1, 2, 3, 4, 5]) v1.transform([2], inc) # pvector([1, 2, 4, 4, 5]) v1.transform([lambda ix: 0 < ix < 4], 8) # pvector([1, 8, 8, 8, 5]) v1.transform([lambda ix, v: ix == 0 or v == 5], 0) # pvector([0, 2, 3, 4, 0]) v1.transform([ny], 8) # pvector([8, 8, 8, 8, 8]) scores = freeze({'John': 12, 'Joseph': 34, 'Sara': 23}) scores.transform([rex('^Jo')], 0) # pmap({'Joseph': 0, 'Sara': 23, 'John': 0}) news_paper = freeze({'articles': [{'author': 'Sara', 'content': 'A short article'}, {'author': 'Steve', 'content': 'A slightly longer article'}], 'weather': {'temperature': '11C', 'wind': '5m/s'}}) short_news = news_paper.transform(['articles', ny, 'content'], lambda c: c[:25] + '...' if len(c) > 25 else c) very_short_news = news_paper.transform(['articles', ny, 'content'], lambda c: c[:15] + '...' if len(c) > 15 else c) # When nothing has been transformed the original data structure is kept # short_news is news_paper # True # very_short_news is news_paper # False # very_short_news.articles[0] is news_paper.articles[0] # True thaw(news_paper.transform(['weather'], discard, ['articles', ny, 'content'], discard)) # {'articles': [{'author': 'Sara'}, {'author': 'Steve'}]} ``` -------------------------------- ### UnicodeDecodeError Fix Source: https://github.com/tobgu/pyrsistent/blob/master/docs/source/changes.rst Resolves a `UnicodeDecodeError` that occurred during `pip install` in environments with ASCII encoding as the default. ```APIDOC pip install: Fixed UnicodeDecodeError in ASCII-default environments. Related: #66 ``` -------------------------------- ### UnicodeDecodeError Fix Source: https://github.com/tobgu/pyrsistent/blob/master/CHANGES.txt Resolves a `UnicodeDecodeError` that occurred during `pip install` in environments with ASCII encoding as the default. ```APIDOC pip install: Fixed UnicodeDecodeError in ASCII-default environments. Related: #66 ``` -------------------------------- ### Python pyrsistent Transformations Source: https://github.com/tobgu/pyrsistent/blob/master/README.rst Demonstrates the use of the `transform` method on pyrsistent data structures (PMaps, PVectors) to modify values at specified paths. Supports index-based paths, callable matchers, regular expressions, and the `ny` (any) matcher for flexible data manipulation. Includes examples of deep transformations and discarding elements. ```python from pyrsistent import inc, freeze, thaw, rex, ny, discard v1 = freeze([1, 2, 3, 4, 5]) v1.transform([2], inc) # pvector([1, 2, 4, 4, 5]) v1.transform([lambda ix: 0 < ix < 4], 8) # pvector([1, 8, 8, 8, 5]) v1.transform([lambda ix, v: ix == 0 or v == 5], 0) # pvector([0, 2, 3, 4, 0]) v1.transform([ny], 8) # pvector([8, 8, 8, 8, 8]) scores = freeze({'John': 12, 'Joseph': 34, 'Sara': 23}) scores.transform([rex('^Jo')], 0) # pmap({'Joseph': 0, 'Sara': 23, 'John': 0}) news_paper = freeze({'articles': [{'author': 'Sara', 'content': 'A short article'}, {'author': 'Steve', 'content': 'A slightly longer article'}], 'weather': {'temperature': '11C', 'wind': '5m/s'}}) short_news = news_paper.transform(['articles', ny, 'content'], lambda c: c[:25] + '...' if len(c) > 25 else c) very_short_news = news_paper.transform(['articles', ny, 'content'], lambda c: c[:15] + '...' if len(c) > 15 else c) # When nothing has been transformed the original data structure is kept # short_news is news_paper # True # very_short_news is news_paper # False # very_short_news.articles[0] is news_paper.articles[0] # True thaw(news_paper.transform(['weather'], discard, ['articles', ny, 'content'], discard)) # {'articles': [{'author': 'Sara'}, {'author': 'Steve'}]} ``` -------------------------------- ### pmap Usage and Evolution Source: https://github.com/tobgu/pyrsistent/blob/master/docs/source/intro.rst Demonstrates the creation, access, transformation, and merging of persistent maps (pmap). Shows how updates create new versions without mutating the original map. ```python from pyrsistent import pmap, m, v # Basic pmap creation and access >>> m1 = pmap({'a': 5, 'c': 3, 'b': 2}) >>> m1['a'] 5 # Evolution of nested persistent structures >>> m4 = m(a=5, b=6, c=v(1, 2)) >>> m4.transform(('c', 1), 17) pmap({'a': 5, 'c': pvector([1, 17]), 'b': 6}) # Evolve by merging with other mappings >>> m5 = m(a=1, b=2) >>> m5.update(m(a=2, c=3), {'a': 17, 'd': 35}) pmap({'a': 17, 'c': 3, 'b': 2, 'd': 35}) >>> pmap({'x': 1, 'y': 2}) + pmap({'y': 3, 'z': 4}) pmap({'y': 3, 'x': 1, 'z': 4}) # Dict-like methods to convert to list and iterate >>> m1.items() pvector([('a', 5), ('c', 3), ('b', 2)]) >>> list(m1) ['a', 'c', 'b'] ``` -------------------------------- ### pmap Usage and Evolution Source: https://github.com/tobgu/pyrsistent/blob/master/README.rst Demonstrates the creation, access, transformation, and merging of persistent maps (pmap). Shows how updates create new versions without mutating the original map. ```python from pyrsistent import pmap, m, v # Basic pmap creation and access >>> m1 = pmap({'a': 5, 'c': 3, 'b': 2}) >>> m1['a'] 5 # Evolution of nested persistent structures >>> m4 = m(a=5, b=6, c=v(1, 2)) >>> m4.transform(('c', 1), 17) pmap({'a': 5, 'c': pvector([1, 17]), 'b': 6}) # Evolve by merging with other mappings >>> m5 = m(a=1, b=2) >>> m5.update(m(a=2, c=3), {'a': 17, 'd': 35}) pmap({'a': 17, 'c': 3, 'b': 2, 'd': 35}) >>> pmap({'x': 1, 'y': 2}) + pmap({'y': 3, 'z': 4}) pmap({'y': 3, 'x': 1, 'z': 4}) # Dict-like methods to convert to list and iterate >>> m1.items() pvector([('a', 5), ('c', 3), ('b', 2)]) >>> list(m1) ['a', 'c', 'b'] ``` -------------------------------- ### PMap/PVector/PSet Construction Source: https://github.com/tobgu/pyrsistent/blob/master/CHANGES.txt Fixes construction from serialized objects for `pvector`, `pset`, and `pmap` fields. ```APIDOC PMap/PVector/PSet Fields: Fixed construction from serialized objects. Related: #38 ``` -------------------------------- ### PMap/PVector/PSet Construction Source: https://github.com/tobgu/pyrsistent/blob/master/docs/source/changes.rst Fixes construction from serialized objects for `pvector`, `pset`, and `pmap` fields. ```APIDOC PMap/PVector/PSet Fields: Fixed construction from serialized objects. Related: #38 ``` -------------------------------- ### PRecord Declaration and Basic Usage Source: https://github.com/tobgu/pyrsistent/blob/master/docs/source/intro.rst Defines and uses a PRecord, a PMap with a fixed set of fields. Demonstrates field access, updates using `set`, and error handling for unknown fields. ```python from pyrsistent import PRecord, field >>> class ARecord(PRecord): ... x = field() ... >>> r = ARecord(x=3) >>> r ARecord(x=3) >>> r.x 3 >>> r.set(x=2) ARecord(x=2) >>> r.set(y=2) Traceback (most recent call last): AttributeError: 'y' is not among the specified fields for ARecord ``` -------------------------------- ### Checked Collections: Lottery and LotteriesByDate Source: https://github.com/tobgu/pyrsistent/blob/master/docs/source/intro.rst Illustrates the definition of checked collections: a Lottery PRecord using a CheckedPSet for numbers, a Lotteries CheckedPVector for Lottery objects, and a LotteriesByDate CheckedPMap mapping dates to Lotteries. This setup enforces type and invariant constraints throughout nested structures. ```python from datetime import date from pyrsistent import PRecord, field, CheckedPSet, CheckedPVector, CheckedPMap, thaw >>> class Positives(CheckedPSet): ... __type__ = (long, int) ... __invariant__ = lambda n: (n >= 0, 'Negative') ... >>> class Lottery(PRecord): ... name = field(type=str) ... numbers = field(type=Positives, invariant=lambda p: (len(p) > 0, 'No numbers')) ... >>> class Lotteries(CheckedPVector): ... __type__ = Lottery ... >>> class LotteriesByDate(CheckedPMap): ... __key_type__ = date ... __value_type__ = Lotteries ... >>> lotteries = LotteriesByDate.create({ ... date(2015, 2, 15): [ ... {'name': 'SuperLotto', 'numbers': {1, 2, 3}}, ... {'name': 'MegaLotto', 'numbers': {4, 5, 6}} ... ], ... date(2015, 2, 16): ... [ ... {'name': 'SuperLotto', 'numbers': {3, 2, 1}}, ... {'name': 'MegaLotto', 'numbers': {6, 5, 4}} ... ] ... }) >>> lotteries LotteriesByDate({datetime.date(2015, 2, 15): Lotteries([Lottery(numbers=Positives([1, 2, 3]), name='SuperLotto'), Lottery(numbers=Positives([4, 5, 6]), name='MegaLotto')]), datetime.date(2015, 2, 16): Lotteries([Lottery(numbers=Positives([1, 2, 3]), name='SuperLotto'), Lottery(numbers=Positives([4, 5, 6]), name='MegaLotto')])}) ``` -------------------------------- ### Checked Collections: Lottery and LotteriesByDate Source: https://github.com/tobgu/pyrsistent/blob/master/README.rst Illustrates the definition of checked collections: a Lottery PRecord using a CheckedPSet for numbers, a Lotteries CheckedPVector for Lottery objects, and a LotteriesByDate CheckedPMap mapping dates to Lotteries. This setup enforces type and invariant constraints throughout nested structures. ```python from datetime import date from pyrsistent import PRecord, field, CheckedPSet, CheckedPVector, CheckedPMap, thaw >>> class Positives(CheckedPSet): ... __type__ = (long, int) ... __invariant__ = lambda n: (n >= 0, 'Negative') ... >>> class Lottery(PRecord): ... name = field(type=str) ... numbers = field(type=Positives, invariant=lambda p: (len(p) > 0, 'No numbers')) ... >>> class Lotteries(CheckedPVector): ... __type__ = Lottery ... >>> class LotteriesByDate(CheckedPMap): ... __key_type__ = date ... __value_type__ = Lotteries ... >>> lotteries = LotteriesByDate.create({ ... date(2015, 2, 15): [ ... {'name': 'SuperLotto', 'numbers': {1, 2, 3}}, ... {'name': 'MegaLotto', 'numbers': {4, 5, 6}} ... ], ... date(2015, 2, 16): ... [ ... {'name': 'SuperLotto', 'numbers': {3, 2, 1}}, ... {'name': 'MegaLotto', 'numbers': {6, 5, 4}} ... ] ... }) >>> lotteries LotteriesByDate({datetime.date(2015, 2, 15): Lotteries([Lottery(numbers=Positives([1, 2, 3]), name='SuperLotto'), Lottery(numbers=Positives([4, 5, 6]), name='MegaLotto')]), datetime.date(2015, 2, 16): Lotteries([Lottery(numbers=Positives([1, 2, 3]), name='SuperLotto'), Lottery(numbers=Positives([4, 5, 6]), name='MegaLotto')])}) ``` -------------------------------- ### PSet Operations Source: https://github.com/tobgu/pyrsistent/blob/master/docs/source/intro.rst Illustrates the creation and manipulation of persistent sets (PSet). Shows how operations like add, remove, union, and intersection return new sets, preserving immutability. ```python from pyrsistent import s # No mutation of sets once created >>> s1 = s(1, 2, 3, 2) # Duplicates are ignored >>> s2 = s1.add(4) >>> s3 = s1.remove(1) >>> s1 pset([1, 2, 3]) >>> s2 pset([1, 2, 3, 4]) >>> s3 pset([2, 3]) # Full support for set operations >>> s1 | s(3, 4, 5) # Union pset([1, 2, 3, 4, 5]) >>> s1 & s(3, 4, 5) # Intersection pset([3]) >>> s1 < s2 # Subset check True >>> s1 < s(3, 4, 5) # Subset check False ``` -------------------------------- ### PVector Comparison Source: https://github.com/tobgu/pyrsistent/blob/master/CHANGES.txt PVector now correctly compares against the built-in Python list type. ```APIDOC PVector Comparison: Now compares against built-in list type. Related: #34 ``` -------------------------------- ### PRecord Field and Global Invariants Source: https://github.com/tobgu/pyrsistent/blob/master/docs/source/intro.rst Illustrates adding invariants to PRecord fields and the record itself. Shows how `InvariantException` is raised for failing invariants, detailing the specific errors. ```python from pyrsistent import PRecord, field, InvariantException >>> class RestrictedVector(PRecord): ... __invariant__ = lambda r: (r.y >= r.x, 'x larger than y') ... x = field(invariant=lambda x: (x > 0, 'x negative')) ... y = field(invariant=lambda y: (y > 0, 'y negative')) ... >>> r = RestrictedVector(y=3, x=2) >>> try: ... r.set(x=-1, y=-2) ... except InvariantException as e: ... print(e.invariant_errors) ... ('y negative', 'x negative') >>> try: ... r.set(x=2, y=1) ... except InvariantException as e: ... print(e.invariant_errors) ... ('x larger than y',) ``` -------------------------------- ### PRecord Declaration and Basic Usage Source: https://github.com/tobgu/pyrsistent/blob/master/README.rst Defines and uses a PRecord, a PMap with a fixed set of fields. Demonstrates field access, updates using `set`, and error handling for unknown fields. ```python from pyrsistent import PRecord, field >>> class ARecord(PRecord): ... x = field() ... >>> r = ARecord(x=3) >>> r ARecord(x=3) >>> r.x 3 >>> r.set(x=2) ARecord(x=2) >>> r.set(y=2) Traceback (most recent call last): AttributeError: 'y' is not among the specified fields for ARecord ``` -------------------------------- ### PRecord Field Factories and Nested Creation Source: https://github.com/tobgu/pyrsistent/blob/master/README.rst Demonstrates how to specify factory functions for fields within a PRecord, such as converting input to integers. It also shows how PRecords handle nested PRecord creation automatically when a field is typed as another PRecord and no explicit factory is provided. ```python from pyrsistent import PRecord, field >>> class DRecord(PRecord): ... x = field(factory=int) ... >>> class ERecord(PRecord): ... d = field(type=DRecord) ... >>> ERecord.create({'d': {'x': '1'}}) ERecord(d=DRecord(x=1)) ``` -------------------------------- ### PMap and PVector Method Changes Source: https://github.com/tobgu/pyrsistent/blob/master/docs/source/changes.rst PMap and PVector methods `values()`, `keys()`, and `items()` now return PVectors instead of Python lists. Ordering is explicitly disallowed for PMap and PBag. ```APIDOC PMap: values(), keys(), items(): Now return PVectors. Ordering: Explicitly disallowed. PVector: values(), keys(), items(): Now return PVectors. Related: #37, #39 ``` -------------------------------- ### Serialization and Pickling Source: https://github.com/tobgu/pyrsistent/blob/master/CHANGES.txt Enables multi-level serialization for checked types and supports pickling of PClasses and PRecords when using `pmap_field`, `pvector_field`, and `pset_field`. ```APIDOC Serialization: Multi-level serialization for checked types. Related: v0.9.1 Pickling: Supports pickling of PClasses and PRecords using pmap_field, pvector_field, and pset_field. Related: #57 ``` -------------------------------- ### PSet Operations Source: https://github.com/tobgu/pyrsistent/blob/master/README.rst Illustrates the creation and manipulation of persistent sets (PSet). Shows how operations like add, remove, union, and intersection return new sets, preserving immutability. ```python from pyrsistent import s # No mutation of sets once created >>> s1 = s(1, 2, 3, 2) # Duplicates are ignored >>> s2 = s1.add(4) >>> s3 = s1.remove(1) >>> s1 pset([1, 2, 3]) >>> s2 pset([1, 2, 3, 4]) >>> s3 pset([2, 3]) # Full support for set operations >>> s1 | s(3, 4, 5) # Union pset([1, 2, 3, 4, 5]) >>> s1 & s(3, 4, 5) # Intersection pset([3]) >>> s1 < s2 # Subset check True >>> s1 < s(3, 4, 5) # Subset check False ``` -------------------------------- ### PVector and PMap Update Methods Source: https://github.com/tobgu/pyrsistent/blob/master/CHANGES.txt Introduces the deprecation of `set_in()` for PVector and PMap, recommending the use of `transform()` instead. `set_in()` has been updated to use `transform()` internally, potentially altering behavior in some edge cases. ```python from pyrsistent import pvector, pmap # Deprecated usage # old_vector = pvector([1, 2, 3]) # new_vector = old_vector.set_in([1], 99) # Recommended usage old_vector = pvector([1, 2, 3]) new_vector = old_vector.transform([1], 99) old_map = pmap({'a': 1, 'b': 2}) new_map = old_map.transform(['b'], 99) ``` -------------------------------- ### PVector and PMap Update Methods Source: https://github.com/tobgu/pyrsistent/blob/master/docs/source/changes.rst Introduces the deprecation of `set_in()` for PVector and PMap, recommending the use of `transform()` instead. `set_in()` has been updated to use `transform()` internally, potentially altering behavior in some edge cases. ```python from pyrsistent import pvector, pmap # Deprecated usage # old_vector = pvector([1, 2, 3]) # new_vector = old_vector.set_in([1], 99) # Recommended usage old_vector = pvector([1, 2, 3]) new_vector = old_vector.transform([1], 99) old_map = pmap({'a': 1, 'b': 2}) new_map = old_map.transform(['b'], 99) ``` -------------------------------- ### PMap and PVector Method Changes Source: https://github.com/tobgu/pyrsistent/blob/master/CHANGES.txt PMap and PVector methods `values()`, `keys()`, and `items()` now return PVectors instead of Python lists. Ordering is explicitly disallowed for PMap and PBag. ```APIDOC PMap: values(), keys(), items(): Now return PVectors. Ordering: Explicitly disallowed. PVector: values(), keys(), items(): Now return PVectors. Related: #37, #39 ``` -------------------------------- ### Serialization and Pickling Source: https://github.com/tobgu/pyrsistent/blob/master/docs/source/changes.rst Enables multi-level serialization for checked types and supports pickling of PClasses and PRecords when using `pmap_field`, `pvector_field`, and `pset_field`. ```APIDOC Serialization: Multi-level serialization for checked types. Related: v0.9.1 Pickling: Supports pickling of PClasses and PRecords using pmap_field, pvector_field, and pset_field. Related: #57 ``` -------------------------------- ### PRecord Field and Global Invariants Source: https://github.com/tobgu/pyrsistent/blob/master/README.rst Illustrates adding invariants to PRecord fields and the record itself. Shows how `InvariantException` is raised for failing invariants, detailing the specific errors. ```python from pyrsistent import PRecord, field, InvariantException >>> class RestrictedVector(PRecord): ... __invariant__ = lambda r: (r.y >= r.x, 'x larger than y') ... x = field(invariant=lambda x: (x > 0, 'x negative')) ... y = field(invariant=lambda y: (y > 0, 'y negative')) ... >>> r = RestrictedVector(y=3, x=2) >>> try: ... r.set(x=-1, y=-2) ... except InvariantException as e: ... print(e.invariant_errors) ... ('y negative', 'x negative') >>> try: ... r.set(x=2, y=1) ... except InvariantException as e: ... print(e.invariant_errors) ... ('x larger than y',) ``` -------------------------------- ### PVector Comparison Source: https://github.com/tobgu/pyrsistent/blob/master/docs/source/changes.rst PVector now correctly compares against the built-in Python list type. ```APIDOC PVector Comparison: Now compares against built-in list type. Related: #34 ``` -------------------------------- ### PClass and PRecord Field Creation Source: https://github.com/tobgu/pyrsistent/blob/master/CHANGES.txt Introduces convenience functions `pvector_field`, `pmap_field`, and `pset_field` for creating fields in PRecord and PClass that enforce checked collections. Also notes the public availability of `PClassMeta` for subclassing. ```APIDOC Field Creation for Checked Collections: pvector_field() pmap_field() pset_field() Used to create fields for PRecord/PClass. Related: #26, #36 PClassMeta: Made public for friendlier subclassing. ``` -------------------------------- ### PRecord Field Factories and Nested Creation Source: https://github.com/tobgu/pyrsistent/blob/master/docs/source/intro.rst Demonstrates how to specify factory functions for fields within a PRecord, such as converting input to integers. It also shows how PRecords handle nested PRecord creation automatically when a field is typed as another PRecord and no explicit factory is provided. ```python from pyrsistent import PRecord, field >>> class DRecord(PRecord): ... x = field(factory=int) ... >>> class ERecord(PRecord): ... d = field(type=DRecord) ... >>> ERecord.create({'d': {'x': '1'}}) ERecord(d=DRecord(x=1)) ``` -------------------------------- ### PClass and PRecord Field Creation Source: https://github.com/tobgu/pyrsistent/blob/master/docs/source/changes.rst Introduces convenience functions `pvector_field`, `pmap_field`, and `pset_field` for creating fields in PRecord and PClass that enforce checked collections. Also notes the public availability of `PClassMeta` for subclassing. ```APIDOC Field Creation for Checked Collections: pvector_field() pmap_field() pset_field() Used to create fields for PRecord/PClass. Related: #26, #36 PClassMeta: Made public for friendlier subclassing. ``` -------------------------------- ### PRecord Serialization with Custom Functions Source: https://github.com/tobgu/pyrsistent/blob/master/docs/source/intro.rst Shows how to implement custom serialization for PRecord fields, particularly for types like datetime.date. A serializer function is defined to format the date into a string based on a provided format dictionary, enabling flexible data output. ```python from datetime import date from pyrsistent import PRecord, field >>> class Person(PRecord): ... name = field(type=unicode) ... birth_date = field(type=date, ... serializer=lambda format, d: d.strftime(format['date'])) ... >>> john = Person(name=u'John', birth_date=date(1985, 10, 21)) >>> john.serialize({'date': '%Y-%m-%d'}) {'birth_date': '1985-10-21', 'name': u'John'} ``` -------------------------------- ### PVectorEvolver Delete Support Source: https://github.com/tobgu/pyrsistent/blob/master/docs/source/changes.rst Provides complete support for the `delete` operation on the C-implementation of `PVectorEvolver`. ```APIDOC PVectorEvolver: Complete support for delete operation on C-implementation. Related: #42 ``` -------------------------------- ### PRecord Serialization with Custom Functions Source: https://github.com/tobgu/pyrsistent/blob/master/README.rst Shows how to implement custom serialization for PRecord fields, particularly for types like datetime.date. A serializer function is defined to format the date into a string based on a provided format dictionary, enabling flexible data output. ```python from datetime import date from pyrsistent import PRecord, field >>> class Person(PRecord): ... name = field(type=unicode) ... birth_date = field(type=date, ... serializer=lambda format, d: d.strftime(format['date'])) ... >>> john = Person(name=u'John', birth_date=date(1985, 10, 21)) >>> john.serialize({'date': '%Y-%m-%d'}) {'birth_date': '1985-10-21', 'name': u'John'} ``` -------------------------------- ### Type Error Handling and Support Source: https://github.com/tobgu/pyrsistent/blob/master/CHANGES.txt Enhances type error reporting from checked types for more informative messages. Adds support for multiple optional types and renames `PRecordTypeError` to `PTypeError`. ```APIDOC Type Errors: More informative messages from checked types. Related: #30 Optional Types: Support for multiple optional types. Related: #28 Exception Renaming: PRecordTypeError -> PTypeError Also raised by PClass. ``` -------------------------------- ### Type Error Handling and Support Source: https://github.com/tobgu/pyrsistent/blob/master/docs/source/changes.rst Enhances type error reporting from checked types for more informative messages. Adds support for multiple optional types and renames `PRecordTypeError` to `PTypeError`. ```APIDOC Type Errors: More informative messages from checked types. Related: #30 Optional Types: Support for multiple optional types. Related: #28 Exception Renaming: PRecordTypeError -> PTypeError Also raised by PClass. ``` -------------------------------- ### Weak References Source: https://github.com/tobgu/pyrsistent/blob/master/CHANGES.txt Enables the creation of weak references to all collection types within the library. ```APIDOC Weak References: Possible to create for all collection types. Related: #58 ``` -------------------------------- ### PVectorEvolver Delete Support Source: https://github.com/tobgu/pyrsistent/blob/master/CHANGES.txt Provides complete support for the `delete` operation on the C-implementation of `PVectorEvolver`. ```APIDOC PVectorEvolver: Complete support for delete operation on C-implementation. Related: #42 ``` -------------------------------- ### PMap and PVector Update/Merge Methods Source: https://github.com/tobgu/pyrsistent/blob/master/CHANGES.txt The methods `merge()` and `merge_with()` on PMap have been renamed to `update()` and `update_with()` respectively. The older names are kept for compatibility but are marked for removal in version 1.0. ```python from pyrsistent import pmap map1 = pmap({'a': 1, 'b': 2}) map2 = pmap({'b': 3, 'c': 4}) # Using new names updated_map = map1.update(map2) print(f"Updated map: {updated_map}") # Using old names (deprecated) # merged_map = map1.merge(map2) # print(f"Merged map: {merged_map}") ``` -------------------------------- ### PRecord Mandatory Fields and InvariantException Source: https://github.com/tobgu/pyrsistent/blob/master/docs/source/intro.rst Demonstrates how to define mandatory fields in a PRecord. Shows that attempting to discard a mandatory field raises an `InvariantException` with missing fields information. ```python from pyrsistent import PRecord, field, InvariantException >>> class CRecord(PRecord): ... x = field(mandatory=True) ... >>> r = CRecord(x=3) >>> try: ... r.discard('x') ... except InvariantException as e: ... print(e.missing_fields) ... ('CRecord.x',) ``` -------------------------------- ### Python 3.2 Compatibility Source: https://github.com/tobgu/pyrsistent/blob/master/CHANGES.txt Removes the test build for Python 3.2 from Travis CI, indicating that while compatibility is not broken, future efforts to maintain it will cease. ```APIDOC Python 3.2: Removed test build from Travis CI. Future compatibility maintenance will cease. ``` -------------------------------- ### Pyrsistent PVector: Immutable List Operations Source: https://github.com/tobgu/pyrsistent/blob/master/README.rst Demonstrates the creation and manipulation of Pyrsistent PVectors, which are immutable list-like collections. Operations like append and set return new vectors, leaving the original untouched. Supports random access, slicing, and iteration. ```python from pyrsistent import v, pvector # No mutation of vectors once created, instead they # are "evolved" leaving the original untouched >>> v1 = v(1, 2, 3) >>> v2 = v1.append(4) >>> v3 = v2.set(1, 5) >>> v1 pvector([1, 2, 3]) >>> v2 pvector([1, 2, 3, 4]) >>> v3 pvector([1, 5, 3, 4]) # Random access and slicing >>> v3[1] 5 >>> v3[1:3] pvector([5, 3]) # Iteration >>> list(x + 1 for x in v3) [2, 6, 4, 5] >>> pvector(2 * x for x in range(3)) pvector([0, 2, 4]) ``` -------------------------------- ### PMap and PSet Copy Functions Source: https://github.com/tobgu/pyrsistent/blob/master/CHANGES.txt PMap and PSet now include a `copy()` function to mimic the interface of Python's built-in `dict` and `set`. These functions return a reference to `self` as the collections are already persistent. ```python from pyrsistent import pmap, pset my_pmap = pmap({'a': 1}) copied_pmap = my_pmap.copy() print(f"Is copied_pmap the same object as my_pmap? {copied_pmap is my_pmap}") my_pset = pset({1, 2}) copied_pset = my_pset.copy() print(f"Is copied_pset the same object as my_pset? {copied_pset is my_pset}") ``` -------------------------------- ### Weak References Source: https://github.com/tobgu/pyrsistent/blob/master/docs/source/changes.rst Enables the creation of weak references to all collection types within the library. ```APIDOC Weak References: Possible to create for all collection types. Related: #58 ``` -------------------------------- ### PMap and PSet Copy Functions Source: https://github.com/tobgu/pyrsistent/blob/master/docs/source/changes.rst PMap and PSet now include a `copy()` function to mimic the interface of Python's built-in `dict` and `set`. These functions return a reference to `self` as the collections are already persistent. ```python from pyrsistent import pmap, pset my_pmap = pmap({'a': 1}) copied_pmap = my_pmap.copy() print(f"Is copied_pmap the same object as my_pmap? {copied_pmap is my_pmap}") my_pset = pset({1, 2}) copied_pset = my_pset.copy() print(f"Is copied_pset the same object as my_pset? {copied_pset is my_pset}") ``` -------------------------------- ### PRecord Mandatory Fields and InvariantException Source: https://github.com/tobgu/pyrsistent/blob/master/README.rst Demonstrates how to define mandatory fields in a PRecord. Shows that attempting to discard a mandatory field raises an `InvariantException` with missing fields information. ```python from pyrsistent import PRecord, field, InvariantException >>> class CRecord(PRecord): ... x = field(mandatory=True) ... >>> r = CRecord(x=3) >>> try: ... r.discard('x') ... except InvariantException as e: ... print(e.missing_fields) ... ('CRecord.x',) ``` -------------------------------- ### Python 3.2 Compatibility Source: https://github.com/tobgu/pyrsistent/blob/master/docs/source/changes.rst Removes the test build for Python 3.2 from Travis CI, indicating that while compatibility is not broken, future efforts to maintain it will cease. ```APIDOC Python 3.2: Removed test build from Travis CI. Future compatibility maintenance will cease. ``` -------------------------------- ### PMap Reallocation Fix Source: https://github.com/tobgu/pyrsistent/blob/master/CHANGES.txt Addresses a bug causing potential element loss during PMap reallocation. ```APIDOC PMap Reallocation: Fixed bug causing potential element loss. Related: v0.11.2 ``` -------------------------------- ### PMap and PVector Update/Merge Methods Source: https://github.com/tobgu/pyrsistent/blob/master/docs/source/changes.rst The methods `merge()` and `merge_with()` on PMap have been renamed to `update()` and `update_with()` respectively. The older names are kept for compatibility but are marked for removal in version 1.0. ```python from pyrsistent import pmap map1 = pmap({'a': 1, 'b': 2}) map2 = pmap({'b': 3, 'c': 4}) # Using new names updated_map = map1.update(map2) print(f"Updated map: {updated_map}") # Using old names (deprecated) # merged_map = map1.merge(map2) # print(f"Merged map: {merged_map}") ``` -------------------------------- ### Pyrsistent PVector: Immutable List Operations Source: https://github.com/tobgu/pyrsistent/blob/master/docs/source/intro.rst Demonstrates the creation and manipulation of Pyrsistent PVectors, which are immutable list-like collections. Operations like append and set return new vectors, leaving the original untouched. Supports random access, slicing, and iteration. ```python from pyrsistent import v, pvector # No mutation of vectors once created, instead they # are "evolved" leaving the original untouched >>> v1 = v(1, 2, 3) >>> v2 = v1.append(4) >>> v3 = v2.set(1, 5) >>> v1 pvector([1, 2, 3]) >>> v2 pvector([1, 2, 3, 4]) >>> v3 pvector([1, 5, 3, 4]) # Random access and slicing >>> v3[1] 5 >>> v3[1:3] pvector([5, 3]) # Iteration >>> list(x + 1 for x in v3) [2, 6, 4, 5] >>> pvector(2 * x for x in range(3)) pvector([0, 2, 4]) ``` -------------------------------- ### Python pyrsistent Evolvers Source: https://github.com/tobgu/pyrsistent/blob/master/docs/source/intro.rst Explains the concept of 'evolvers' in pyrsistent, which act as mutable views for persistent data structures like PVector, PMap, and PSet. Evolvers allow for efficient batch updates with transaction-like semantics before committing changes to a new persistent structure, while the original remains immutable. ```python from pyrsistent import v v1 = v(1, 2, 3) e = v1.evolver() e[1] = 22 e = e.append(4) e = e.extend([5, 6]) e[5] += 1 # len(e) is 6 # The evolver is considered *dirty* when it contains changes compared to the underlying vector # e.is_dirty() # True # But the underlying pvector still remains untouched # v1 # pvector([1, 2, 3]) # Once satisfied with the updates you can produce a new pvector containing the updates. v2 = e.persistent() # v2 # pvector([1, 22, 3, 4, 5, 7]) # The evolver is now no longer considered *dirty* as it contains no differences compared to the # new persistent structure it just created. ``` -------------------------------- ### Pyrsistent PMap: Immutable Dictionary Operations Source: https://github.com/tobgu/pyrsistent/blob/master/docs/source/intro.rst Illustrates the usage of Pyrsistent PMaps, which are immutable dictionary-like collections adhering to the Mapping protocol. Similar to PVectors, modifications create new PMap instances instead of altering the original. Supports efficient key-value access and updates. ```python from pyrsistent import m, pmap, v # No mutation of maps once created, instead they are # "evolved" leaving the original untouched >>> m1 = m(a=1, b=2) >>> m2 = m1.set('c', 3) >>> m3 = m2.set('a', 5) >>> m1 pmap({'a': 1, 'b': 2}) >>> m2 pmap({'a': 1, 'c': 3, 'b': 2}) >>> m3 pmap({'a': 5, 'c': 3, 'b': 2}) ``` -------------------------------- ### PRecord Multiple Invariant Assertions Source: https://github.com/tobgu/pyrsistent/blob/master/docs/source/intro.rst Demonstrates how to define multiple invariant assertions for a single PRecord field. Shows that the `invariant_errors` attribute will contain data from all failed invariants. ```python from pyrsistent import PRecord, field >>> class EvenX(PRecord): ... x = field(invariant=lambda x: ((x > 0, 'x negative'), (x % 2 == 0, 'x odd'))) ... ``` -------------------------------- ### PVector Operations Source: https://github.com/tobgu/pyrsistent/blob/master/CHANGES.txt Details the addition of `remove()` to PVector for removing elements and `delete()` for removing elements by index or range, noting that `delete()` performs a full copy without structural sharing. ```APIDOC PVector: remove(element) Removes an element from the vector. delete(index | slice) Removes elements by index or range. Performs a full copy, no structural sharing. Related: #42 ``` -------------------------------- ### Pythonic Renaming: assoc/assoc_in, massoc Source: https://github.com/tobgu/pyrsistent/blob/master/CHANGES.txt Several methods have been renamed to be more Pythonic. `assoc()` is now `set()`, `assoc_in()` is now `set_in()`, and `massoc()` is now `mset()`. These changes were made for better alignment with Python conventions. ```python from pyrsistent import pmap, pvector # PMap renaming my_pmap = pmap({'a': 1}) new_pmap = my_pmap.set('b', 2) # Formerly assoc('b', 2) print(f"PMap after set: {new_pmap}") # PVector renaming my_pvector = pvector([1, 2]) new_pvector = my_pvector.set_in([1], 99) # Formerly assoc_in([1], 99) print(f"PVector after set_in: {new_pvector}") # PMap massoc renaming # new_pmap_mset = my_pmap.mset({'c': 3, 'd': 4}) # Formerly massoc({'c': 3, 'd': 4}) ```