{"id":10247,"library":"spectate","title":"Spectate: Track Mutable Data Changes","description":"Spectate (v1.0.1) is a Python library designed to track changes to mutable data types, providing undo/redo capabilities for operations on objects like dictionaries and lists. It achieves this by wrapping functions that modify tracked objects, recording events for each change. The library is currently feature-complete and in maintenance mode, with a slow release cadence.","status":"active","version":"1.0.1","language":"en","source_language":"en","source_url":"https://github.com/rmorshea/spectate","tags":["data structures","event tracking","observables","undo/redo","mutable data"],"install":[{"cmd":"pip install spectate","lang":"bash","label":"Install stable version"}],"dependencies":[],"imports":[{"symbol":"track","correct":"from spectate import track"},{"symbol":"undo","correct":"from spectate import undo"},{"symbol":"redo","correct":"from spectate import redo"},{"symbol":"rollback","correct":"from spectate import rollback"},{"note":"The `Immutable` class was removed in v1.0.0. Event objects are now standard Python dicts.","wrong":"from spectate.utils import Immutable","symbol":"Immutable","correct":"N/A (removed)"}],"quickstart":{"code":"from spectate import track, undo, redo\n\na = {}\n\n@track(a)\ndef add_entry(key, value):\n    a[key] = value\n\nadd_entry('x', 1)\nadd_entry('y', 2)\nprint(f\"Initial state: {a}\")\n\nundo()\nprint(f\"After first undo: {a}\")\n\nundo()\nprint(f\"After second undo: {a}\")\n\nredo()\nprint(f\"After first redo: {a}\")\n\nredo()\nprint(f\"After second redo: {a}\")","lang":"python","description":"This example demonstrates how to use `spectate.track` to observe changes to a dictionary, and then `undo` and `redo` those changes. The `@track` decorator wraps the `add_entry` function, automatically recording each modification to the dictionary `a`."},"warnings":[{"fix":"Access event data using standard dictionary key notation (e.g., `event['key']`) instead of attribute access (e.g., `event.key`).","message":"Event objects returned by Spectate (e.g., from `spectate.events.current_event()`) are now standard Python dictionaries, not `Immutable` (dict-like) objects with attribute access.","severity":"breaking","affected_versions":"1.0.0+"},{"fix":"Remove any direct imports or references to `spectate.utils.Immutable`. If you were creating custom immutable objects, you'll need to refactor to use standard Python dicts or create your own immutable wrappers.","message":"The `spectate.utils.Immutable` class has been completely removed.","severity":"breaking","affected_versions":"1.0.0+"},{"fix":"Ensure `spectate.events.rollback()` is called with the `undo` parameter, e.g., `spectate.events.rollback(undo_action_function)`.","message":"The `undo` parameter for `spectate.events.rollback()` is now required.","severity":"breaking","affected_versions":"1.0.0+"}],"env_vars":null,"last_verified":"2026-04-17T00:00:00.000Z","next_check":"2026-07-16T00:00:00.000Z","problems":[{"fix":"Access event data using dictionary key notation: `event['some_attribute']`.","cause":"Attempting attribute access on an event object (e.g., `event.foo`) after upgrading to spectate v1.0.0+, where event objects are standard Python dictionaries.","error":"AttributeError: 'dict' object has no attribute 'some_attribute'"},{"fix":"Remove the `from spectate.utils import Immutable` statement. Spectate no longer uses this class internally, and event objects are now standard dictionaries.","cause":"Trying to import the `Immutable` class, which was removed from `spectate.utils` in v1.0.0.","error":"ImportError: cannot import name 'Immutable' from 'spectate.utils'"},{"fix":"Pass the `undo` argument when calling `spectate.events.rollback()`, for example: `spectate.events.rollback(my_undo_function)`.","cause":"Calling `spectate.events.rollback()` without providing the mandatory `undo` argument, which was introduced in v1.0.0.","error":"TypeError: rollback() missing 1 required positional argument: 'undo'"}]}