{"library":"persistent","title":"Persistent Objects Base Class","description":"The `persistent` library provides a base class, `Persistent`, for creating translucent persistent Python objects. These objects can track their their own 'dirty' state, indicating when they have been modified and need to be saved by an external persistence layer (e.g., ZODB). It is a fundamental component for building object persistence systems. The current version is 6.5, with major releases typically aligning with Python version support updates and addressing core behavior changes.","language":"python","status":"active","last_verified":"Sun May 17","install":{"commands":["pip install persistent"],"cli":null},"imports":["from persistent import Persistent"],"auth":{"required":false,"env_vars":[]},"quickstart":{"code":"from persistent import Persistent\n\nclass MyPersistentObject(Persistent):\n    def __init__(self, name=\"Default\"):\n        self.name = name\n        self.attributes = {} # A mutable dictionary\n\n    def update_name(self, new_name):\n        # Assigning to a direct attribute will mark the object dirty\n        self.name = new_name\n\n    def add_attribute(self, key, value):\n        # For objects managed by a persistence layer (e.g., ZODB), \n        # modifying this dict would also mark the parent dirty. \n        # Without a persistence layer, direct dict modification here\n        # does NOT automatically set _p_changed.\n        self.attributes[key] = value\n\n    def describe(self):\n        return f\"Name: {self.name}, Attributes: {self.attributes}\"\n\n# Create an instance\nmy_obj = MyPersistentObject(\"Initial Name\")\nprint(f\"1. Initial state: {my_obj.describe()}, _p_changed: {my_obj._p_changed}\")\n\n# Modifying a direct attribute marks it dirty\nmy_obj.update_name(\"New Name 1\")\nprint(f\"2. After update_name: {my_obj.describe()}, _p_changed: {my_obj._p_changed}\")\n\n# Simulate 'saving' (a persistence layer would set _p_changed to None)\nmy_obj._p_changed = None\nprint(f\"3. After 'saving': {my_obj.describe()}, _p_changed: {my_obj._p_changed}\")\n\n# Modifying the mutable dictionary directly (without a storage proxy)\n# does NOT automatically set _p_changed, which is a common gotcha.\nmy_obj.attributes['version'] = 1\nprint(f\"4. After modifying internal dict: {my_obj.describe()}, _p_changed: {my_obj._p_changed}\")\n\n# To ensure persistence layer detects changes in mutable objects,\n# you often need to manually set _p_changed or reassign the attribute\n# (e.g., obj.attributes = new_dict_or_copy) or rely on a proxy provided by the storage.\nmy_obj._p_changed = True\nprint(f\"5. Manually set _p_changed after internal change: {my_obj.describe()}, _p_changed: {my_obj._p_changed}\")","lang":"python","description":"Demonstrates the basic usage of `persistent.Persistent` by subclassing it and observing how its `_p_changed` attribute is affected by direct attribute assignments. It also highlights a common gotcha regarding changes to mutable attributes within the object when not managed by a full persistence layer.","tag":null,"tag_description":null,"last_tested":null,"results":[]},"compatibility":{"tag":null,"tag_description":null,"last_tested":"2026-05-17","installed_version":"6.3","pypi_latest":"6.6","is_stale":true,"summary":{"python_range":"3.10–3.9","success_rate":50,"avg_install_s":2.4,"avg_import_s":0.05,"wheel_type":"wheel"},"results":[{"runtime":"python:3.10-alpine","python_version":"3.10","os_libc":"alpine (musl)","variant":"persistent","exit_code":1,"wheel_type":null,"failure_reason":"build_error","import_side_effects":null,"install_time_s":null,"import_time_s":null,"mem_mb":null,"disk_size":null},{"runtime":"python:3.10-slim","python_version":"3.10","os_libc":"slim (glibc)","variant":"persistent","exit_code":0,"wheel_type":"wheel","failure_reason":null,"import_side_effects":"clean","install_time_s":2.5,"import_time_s":0.04,"mem_mb":2.7,"disk_size":"24M"},{"runtime":"python:3.11-alpine","python_version":"3.11","os_libc":"alpine (musl)","variant":"persistent","exit_code":1,"wheel_type":null,"failure_reason":"build_error","import_side_effects":null,"install_time_s":null,"import_time_s":null,"mem_mb":null,"disk_size":null},{"runtime":"python:3.11-slim","python_version":"3.11","os_libc":"slim (glibc)","variant":"persistent","exit_code":0,"wheel_type":"wheel","failure_reason":null,"import_side_effects":"clean","install_time_s":2.3,"import_time_s":0.07,"mem_mb":2.8,"disk_size":"26M"},{"runtime":"python:3.12-alpine","python_version":"3.12","os_libc":"alpine (musl)","variant":"persistent","exit_code":1,"wheel_type":null,"failure_reason":"build_error","import_side_effects":null,"install_time_s":null,"import_time_s":null,"mem_mb":null,"disk_size":null},{"runtime":"python:3.12-slim","python_version":"3.12","os_libc":"slim (glibc)","variant":"persistent","exit_code":0,"wheel_type":"wheel","failure_reason":null,"import_side_effects":"clean","install_time_s":2.1,"import_time_s":0.06,"mem_mb":2.5,"disk_size":"18M"},{"runtime":"python:3.13-alpine","python_version":"3.13","os_libc":"alpine (musl)","variant":"persistent","exit_code":1,"wheel_type":null,"failure_reason":"build_error","import_side_effects":null,"install_time_s":null,"import_time_s":null,"mem_mb":null,"disk_size":null},{"runtime":"python:3.13-slim","python_version":"3.13","os_libc":"slim (glibc)","variant":"persistent","exit_code":0,"wheel_type":"wheel","failure_reason":null,"import_side_effects":"clean","install_time_s":2.2,"import_time_s":0.06,"mem_mb":2.5,"disk_size":"18M"},{"runtime":"python:3.9-alpine","python_version":"3.9","os_libc":"alpine (musl)","variant":"persistent","exit_code":1,"wheel_type":null,"failure_reason":"build_error","import_side_effects":null,"install_time_s":null,"import_time_s":null,"mem_mb":null,"disk_size":null},{"runtime":"python:3.9-slim","python_version":"3.9","os_libc":"slim (glibc)","variant":"persistent","exit_code":0,"wheel_type":"wheel","failure_reason":null,"import_side_effects":"clean","install_time_s":3,"import_time_s":0.04,"mem_mb":2.7,"disk_size":"24M"}]}}