From 1a683cc908eaeeda591a4c7b67fb77316b8eec1d Mon Sep 17 00:00:00 2001 From: Stephen Finucane Date: Thu, 5 Mar 2026 20:09:29 +0000 Subject: [PATCH] base: Swap location of remoteable decorators We are going to rework these significantly in a future change. Move them around ahead of that so that we have a smaller diff. Change-Id: I5c18026606526e7f0a0bef1dc8382fda8ebb3329 Signed-off-by: Stephen Finucane --- oslo_versionedobjects/base.py | 86 +++++++++++++++++------------------ 1 file changed, 42 insertions(+), 44 deletions(-) diff --git a/oslo_versionedobjects/base.py b/oslo_versionedobjects/base.py index 542d3fe7..609ea7e1 100644 --- a/oslo_versionedobjects/base.py +++ b/oslo_versionedobjects/base.py @@ -161,12 +161,52 @@ class VersionedObjectRegistry: return registry._obj_classes -# These are decorators that mark an object's method as remotable. +# Decorator that marks an object's method as remotable. # If the metaclass is configured to forward object methods to an -# indirection service, these will result in making an RPC call +# indirection service, this will result in making an RPC call # instead of directly calling the implementation in the object. Instead, # the object implementation on the remote end will perform the # requested action and the result will be returned here. +# +# Note that for instance methods, if context is not present, the object +# is "orphaned" and remotable methods cannot be called. +def remotable(fn): + """Decorator for remotable object methods.""" + + @functools.wraps(fn) + def wrapper(self, *args, **kwargs): + ctxt = self._context + if ctxt is None: + raise exception.OrphanedObjectError( + method=fn.__name__, objtype=self.obj_name() + ) + if self.indirection_api: + updates, result = self.indirection_api.object_action( + ctxt, self, fn.__name__, args, kwargs + ) + for key, value in updates.items(): + if key in self.fields: + field = self.fields[key] + # NOTE(ndipanov): Since VersionedObjectSerializer will have + # deserialized any object fields into objects already, + # we do not try to deserialize them again here. + if isinstance(value, VersionedObject): + setattr(self, key, value) + else: + setattr( + self, key, field.from_primitive(self, key, value) + ) + self.obj_reset_changes() + self._changed_fields = set(updates.get('obj_what_changed', [])) + return result + else: + return fn(self, *args, **kwargs) + + wrapper.remotable = True + wrapper.original_fn = fn + return wrapper + + def remotable_classmethod(fn): """Decorator for remotable classmethods.""" @@ -205,48 +245,6 @@ def remotable_classmethod(fn): return classmethod(wrapper) -# See comment above for remotable_classmethod() -# -# Note that this will use either the provided context, or the one -# stashed in the object. If neither are present, the object is -# "orphaned" and remotable methods cannot be called. -def remotable(fn): - """Decorator for remotable object methods.""" - - @functools.wraps(fn) - def wrapper(self, *args, **kwargs): - ctxt = self._context - if ctxt is None: - raise exception.OrphanedObjectError( - method=fn.__name__, objtype=self.obj_name() - ) - if self.indirection_api: - updates, result = self.indirection_api.object_action( - ctxt, self, fn.__name__, args, kwargs - ) - for key, value in updates.items(): - if key in self.fields: - field = self.fields[key] - # NOTE(ndipanov): Since VersionedObjectSerializer will have - # deserialized any object fields into objects already, - # we do not try to deserialize them again here. - if isinstance(value, VersionedObject): - setattr(self, key, value) - else: - setattr( - self, key, field.from_primitive(self, key, value) - ) - self.obj_reset_changes() - self._changed_fields = set(updates.get('obj_what_changed', [])) - return result - else: - return fn(self, *args, **kwargs) - - wrapper.remotable = True - wrapper.original_fn = fn - return wrapper - - class VersionedObject: """Base class and object factory.