3838from ..._utils .property_protocols import ReadOnlyProperty , ReadWriteProperty
3939from .polymorphic_from_pb import CreatableFromResourcePath , tree_object_from_resource_path
4040from .protocols import Editable , GrpcObjectBase , ObjectInfo , Readable
41+ from .supported_since import supported_since as supported_since_decorator
4142
4243# Note: The typing of the protobuf objects is fairly loose, maybe it could
4344# be improved. The main challenge is that we do not encode the structure of
@@ -110,7 +111,10 @@ def inner(self: Readable) -> CreatableFromResourcePath | None:
110111
111112
112113def grpc_data_getter (
113- name : str , from_protobuf : _FROM_PROTOBUF_T [_GET_T ], check_optional : bool = False
114+ name : str ,
115+ from_protobuf : _FROM_PROTOBUF_T [_GET_T ],
116+ check_optional : bool = False ,
117+ supported_since : str | None = None ,
114118) -> Callable [[Readable ], _GET_T ]:
115119 """Create a getter method which obtains the server object via the gRPC Get endpoint.
116120
@@ -125,6 +129,14 @@ def grpc_data_getter(
125129 will be used.
126130 """
127131
132+ @supported_since_decorator (
133+ supported_since ,
134+ # The default error message uses 'inner' as the method name, which is confusing
135+ err_msg_tpl = (
136+ f"The property '{ name .split ('.' )[- 1 ]} ' is only readable since version {{required_version}} "
137+ f"of the ACP gRPC server. The current server version is {{server_version}}."
138+ ),
139+ )
128140 def inner (self : Readable ) -> Any :
129141 self ._get_if_stored ()
130142 pb_attribute = _get_data_attribute (self ._pb_object , name , check_optional = check_optional )
@@ -149,26 +161,6 @@ def inner(self: Editable, value: Readable | None) -> None:
149161 return inner
150162
151163
152- def grpc_data_setter (
153- name : str , to_protobuf : _TO_PROTOBUF_T [_SET_T ]
154- ) -> Callable [[Editable , _SET_T ], None ]:
155- """Create a setter method which updates the server object via the gRPC Put endpoint."""
156-
157- def inner (self : Editable , value : _SET_T ) -> None :
158- self ._get_if_stored ()
159- current_value = _get_data_attribute (self ._pb_object , name )
160- value_pb = to_protobuf (value )
161- try :
162- needs_updating = current_value != value_pb
163- except TypeError :
164- needs_updating = True
165- if needs_updating :
166- _set_data_attribute (self ._pb_object , name , value_pb )
167- self ._put_if_stored ()
168-
169- return inner
170-
171-
172164def _get_data_attribute (pb_obj : Message , name : str , check_optional : bool = False ) -> _PROTOBUF_T :
173165 name_parts = name .split ("." )
174166 if check_optional :
@@ -197,6 +189,37 @@ def _set_data_attribute(pb_obj: ObjectInfo, name: str, value: _PROTOBUF_T) -> No
197189 target_object .add ().CopyFrom (item )
198190
199191
192+ def grpc_data_setter (
193+ name : str ,
194+ to_protobuf : _TO_PROTOBUF_T [_SET_T ],
195+ setter_func : Callable [[ObjectInfo , str , _PROTOBUF_T ], None ] = _set_data_attribute ,
196+ supported_since : str | None = None ,
197+ ) -> Callable [[Editable , _SET_T ], None ]:
198+ """Create a setter method which updates the server object via the gRPC Put endpoint."""
199+
200+ @supported_since_decorator (
201+ supported_since ,
202+ # The default error message uses 'inner' as the method name, which is confusing
203+ err_msg_tpl = (
204+ f"The property '{ name .split ('.' )[- 1 ]} ' is only editable since version {{required_version}} "
205+ f"of the ACP gRPC server. The current server version is {{server_version}}."
206+ ),
207+ )
208+ def inner (self : Editable , value : _SET_T ) -> None :
209+ self ._get_if_stored ()
210+ current_value = _get_data_attribute (self ._pb_object , name )
211+ value_pb = to_protobuf (value )
212+ try :
213+ needs_updating = current_value != value_pb
214+ except TypeError :
215+ needs_updating = True
216+ if needs_updating :
217+ setter_func (self ._pb_object , name , value_pb )
218+ self ._put_if_stored ()
219+
220+ return inner
221+
222+
200223AnyT = TypeVar ("AnyT" )
201224
202225
@@ -212,6 +235,9 @@ def grpc_data_property(
212235 from_protobuf : _FROM_PROTOBUF_T [_GET_T ] = lambda x : x ,
213236 check_optional : bool = False ,
214237 doc : str | None = None ,
238+ setter_func : Callable [[ObjectInfo , str , _PROTOBUF_T ], None ] = _set_data_attribute ,
239+ readable_since : str | None = None ,
240+ writable_since : str | None = None ,
215241) -> ReadWriteProperty [_GET_T , _SET_T ]:
216242 """Define a property which is synchronized with the backend via gRPC.
217243
@@ -234,6 +260,10 @@ def grpc_data_property(
234260 will be used.
235261 doc :
236262 Docstring for the property.
263+ readable_since :
264+ Version since which the property is supported for reading.
265+ writable_since :
266+ Version since which the property is supported for setting.
237267 """
238268 # Note jvonrick August 2023: We don't ensure with typechecks that the property returned here is
239269 # compatible with the class on which this property is created. For example:
@@ -244,8 +274,20 @@ def grpc_data_property(
244274 # https://github.com/python/typing/issues/985
245275 return _wrap_doc (
246276 _exposed_grpc_property (
247- grpc_data_getter (name , from_protobuf = from_protobuf , check_optional = check_optional )
248- ).setter (grpc_data_setter (name , to_protobuf = to_protobuf )),
277+ grpc_data_getter (
278+ name ,
279+ from_protobuf = from_protobuf ,
280+ check_optional = check_optional ,
281+ supported_since = readable_since ,
282+ )
283+ ).setter (
284+ grpc_data_setter (
285+ name ,
286+ to_protobuf = to_protobuf ,
287+ setter_func = setter_func ,
288+ supported_since = writable_since ,
289+ )
290+ ),
249291 doc = doc ,
250292 )
251293
@@ -255,6 +297,7 @@ def grpc_data_property_read_only(
255297 from_protobuf : _FROM_PROTOBUF_T [_GET_T ] = lambda x : x ,
256298 check_optional : bool = False ,
257299 doc : str | None = None ,
300+ supported_since : str | None = None ,
258301) -> ReadOnlyProperty [_GET_T ]:
259302 """Define a read-only property which is synchronized with the backend via gRPC.
260303
@@ -275,10 +318,17 @@ def grpc_data_property_read_only(
275318 will be used.
276319 doc :
277320 Docstring for the property.
321+ supported_since :
322+ Version since which the property is supported.
278323 """
279324 return _wrap_doc (
280325 _exposed_grpc_property (
281- grpc_data_getter (name , from_protobuf = from_protobuf , check_optional = check_optional )
326+ grpc_data_getter (
327+ name ,
328+ from_protobuf = from_protobuf ,
329+ check_optional = check_optional ,
330+ supported_since = supported_since ,
331+ )
282332 ),
283333 doc = doc ,
284334 )
0 commit comments