{"id":9162,"library":"oslo-versionedobjects","title":"Oslo Versioned Objects","description":"Oslo Versioned Objects is an OpenStack library that provides a framework for defining data objects with built-in versioning capabilities. It allows for seamless evolution of object schemas, particularly important in RPC (Remote Procedure Call) contexts where different service versions might communicate. It's currently at version 3.9.0 and is part of the OpenStack Oslo libraries, receiving updates in sync with OpenStack releases.","status":"active","version":"3.9.0","language":"en","source_language":"en","source_url":"https://github.com/openstack/oslo.versionedobjects","tags":["OpenStack","objects","versioning","RPC","data-models"],"install":[{"cmd":"pip install oslo-versionedobjects","lang":"bash","label":"Install stable version"}],"dependencies":[{"reason":"Core utility library for OpenStack projects, used for logging, i18n, etc.","package":"oslo.utils","optional":false},{"reason":"Configuration management library for OpenStack projects.","package":"oslo.config","optional":false}],"imports":[{"note":"The top-level package is `oslo_versionedobjects`, not `oslo.versionedobjects`.","wrong":"from oslo.versionedobjects import base","symbol":"VersionedObject","correct":"from oslo_versionedobjects import base"},{"note":"Field types (StringField, IntegerField, etc.) are imported from `oslo_versionedobjects.fields`.","wrong":"from oslo.versionedobjects import fields","symbol":"Field","correct":"from oslo_versionedobjects import fields"},{"note":"The serializer is part of the base module for object primitives.","wrong":"from oslo.versionedobjects import base","symbol":"VersionedObjectSerializer","correct":"from oslo_versionedobjects import base"}],"quickstart":{"code":"import uuid\nfrom oslo_versionedobjects import base, fields\n\n# 1. Define your VersionedObject\nclass MyExampleObject(base.VersionedObject):\n    # The current version of this object schema.\n    # Increment this when making backwards-incompatible changes.\n    VERSION = '1.0'\n\n    # Define the fields for your object\n    fields = {\n        'id': fields.UUIDField(),\n        'name': fields.StringField(nullable=False),\n        'status': fields.StringField(default='active'),\n        'value': fields.IntegerField(nullable=True, default=0),\n    }\n\n    # Optional: Override __init__ to set defaults or perform custom logic\n    def __init__(self, context=None, **kwargs):\n        super().__init__(context, **kwargs)\n        # Call obj_set_defaults() to ensure default values from fields are applied.\n        self.obj_set_defaults()\n\n    # Optional: Add methods to your object\n    def activate(self):\n        if self.status != 'active':\n            self.status = 'active'\n            self.obj_make_compatible() # Mark object as changed for serialization\n            print(f\"Object {self.name} activated.\")\n        else:\n            print(f\"Object {self.name} is already active.\")\n\n# 2. Instantiate and use your object\n# Create an instance with some data\nobj_id = str(uuid.uuid4())\nmy_obj = MyExampleObject(id=obj_id, name=\"First Item\", value=100)\n\nprint(f\"Initial object: {my_obj.obj_name} v{my_obj.obj_version}\")\nprint(f\"ID: {my_obj.id}\")\nprint(f\"Name: {my_obj.name}\")\nprint(f\"Status: {my_obj.status}\")\nprint(f\"Value: {my_obj.value}\")\nprint(f\"Is changed? {my_obj.obj_what_changed()}\")\n\nmy_obj.activate()\nprint(f\"Status after activation: {my_obj.status}\")\nprint(f\"Is changed? {my_obj.obj_what_changed()}\")\n\n# 3. Serialize and Deserialize (demonstrates versioning capability)\nserializer = base.VersionedObjectSerializer()\n\n# Convert the object to a primitive (dictionary) for serialization\nprimitive = serializer.serialize_entity(None, my_obj)\nprint(\"\\nSerialized primitive:\")\nprint(primitive)\n\n# Simulate deserialization (e.g., after receiving over RPC)\ndeserialized_obj = serializer.deserialize_entity(None, MyExampleObject, primitive)\nprint(\"\\nDeserialized object:\")\nprint(f\"Name: {deserialized_obj.name}\")\nprint(f\"Status: {deserialized_obj.status}\")\nprint(f\"Value: {deserialized_obj.value}\")\nprint(f\"Are objects equal? {my_obj == deserialized_obj}\")\nprint(f\"Has deserialized object changed? {deserialized_obj.obj_what_changed()}\")","lang":"python","description":"This quickstart demonstrates how to define a basic VersionedObject with fields and methods. It then shows how to instantiate it, modify its state, and finally serialize it to a primitive representation (dictionary) and deserialize it back, illustrating the core versioning and serialization capabilities of the library."},"warnings":[{"fix":"Ensure your Python environment is 3.10 or later. If you need to support older Python versions, pin `oslo-versionedobjects` to `<3.0.0`.","message":"Version 3.0.0 and above of `oslo-versionedobjects` explicitly require Python 3.10 or newer. Previous versions (2.x) supported Python 3.6-3.9.","severity":"breaking","affected_versions":">=3.0.0"},{"fix":"Adapt your object loading logic to no longer use `obj_from_db_object`. Instead, construct the object directly or use `obj_make_compatible` and `obj_from_primitive` with a manually constructed primitive.","message":"The `VersionedObject.obj_from_db_object` method was removed in version 3.0.0. This change affects how objects are loaded from database records, requiring direct initialization or alternative loading mechanisms.","severity":"breaking","affected_versions":">=3.0.0"},{"fix":"Always use `oslo_versionedobjects.base.VersionedObjectSerializer` (or a similar specialized serializer) to convert VOO instances to/from primitive types suitable for JSON serialization, RPC, or database storage.","message":"Directly using `json.dumps()` on a `VersionedObject` instance will often fail with `TypeError: Object of type <YourObject> is not JSON serializable` because VOO instances are complex objects.","severity":"gotcha","affected_versions":"All"}],"env_vars":null,"last_verified":"2026-04-16T00:00:00.000Z","next_check":"2026-07-15T00:00:00.000Z","problems":[{"fix":"Use the provided serializer: `from oslo_versionedobjects import base; serializer = base.VersionedObjectSerializer(); primitive = serializer.serialize_entity(None, my_obj)`","cause":"Attempting to serialize a VersionedObject instance directly using `json.dumps()` or similar standard JSON encoders.","error":"TypeError: Object of type MyExampleObject is not JSON serializable"},{"fix":"Ensure your VersionedObject classes are imported and accessible where deserialization occurs. In OpenStack services, this is often handled by a central manager; for standalone use, ensure all object definitions are loaded.","cause":"The object class (or its specific version) was not properly registered with the VersionedObjectRegistry before deserialization or RPC calls, or there's a mismatch between `obj_name`/`obj_version` and the registered objects.","error":"VersionedObjectNotFound: Object MyExampleObject with version 1.0 could not be found."},{"fix":"Verify that 'some_field' is correctly defined in the `fields` dictionary of `MyExampleObject`. If the object is loaded from a primitive, ensure the primitive contains the field data. For lazy-loaded fields, call `obj_load_attr('some_field')` before access.","cause":"Attempting to access a field that was not defined in the `fields` dictionary of the VersionedObject class, or the field was not loaded (if using lazy-loading from `obj_load_attr`).","error":"AttributeError: 'MyExampleObject' object has no attribute 'some_field'"}]}