crossplane-function-pythonic 0.6.2__py3-none-any.whl → 0.7.0__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -17,81 +17,158 @@
17
17
 
18
18
  import base64
19
19
  import datetime
20
- import google.protobuf.struct_pb2
21
20
  import json
22
21
  import sys
23
- import yaml
22
+ import typing
24
23
 
25
- _Unknown = object()
24
+ import google.protobuf.descriptor
25
+ import google.protobuf.message
26
+ import google.protobuf.struct_pb2
27
+ import yaml
28
+ from google.protobuf.internal.containers import (
29
+ MessageMap,
30
+ RepeatedCompositeFieldContainer,
31
+ RepeatedScalarFieldContainer,
32
+ ScalarMap,
33
+ )
34
+
35
+ type TypeString = str | Value | FieldMessage
36
+ _Unknown = sentinel("_Unknown")
26
37
  append = sys.maxsize
27
38
 
28
39
 
29
- def Map(**kwargs):
40
+ def Map(**kwargs) -> Value:
30
41
  return Value(None, None, kwargs)
31
42
 
32
- def List(*args):
43
+
44
+ def List(*args) -> Value:
33
45
  return Value(None, None, args)
34
46
 
35
- def Unknown():
47
+
48
+ def Unknown() -> Value:
36
49
  return Value(None, None)
37
50
 
38
- def Yaml(string, readOnly=None):
51
+
52
+ def Yaml(string: TypeString, readOnly: str | bool = False) -> Value | FieldMessage:
39
53
  if isinstance(string, (FieldMessage, Value)):
40
54
  if not string:
41
55
  return string
42
56
  string = str(string)
43
57
  return Value(None, None, yaml.safe_load(string), readOnly)
44
58
 
45
- def YamlAll(string, readOnly=None):
59
+
60
+ def YamlAll(string: TypeString, readOnly: str | bool = False) -> Value | FieldMessage:
46
61
  if isinstance(string, (FieldMessage, Value)):
47
62
  if not string:
48
63
  return string
49
64
  string = str(string)
50
- return Value(None, None, [document for document in yaml.safe_load_all(string)], readOnly)
65
+ return Value(
66
+ None, None, [document for document in yaml.safe_load_all(string)], readOnly
67
+ )
51
68
 
52
- def Json(string, readOnly=None):
69
+
70
+ def Json(string: TypeString, readOnly: str | bool = False) -> Value | FieldMessage:
53
71
  if isinstance(string, (FieldMessage, Value)):
54
72
  if not string:
55
73
  return string
56
74
  string = str(string)
57
75
  return Value(None, None, json.loads(string), readOnly)
58
76
 
59
- def B64Encode(string):
77
+
78
+ def B64Encode(string: TypeString) -> TypeString:
60
79
  if isinstance(string, (FieldMessage, Value)):
61
80
  if not string:
62
81
  return string
63
82
  string = str(string)
64
- return base64.b64encode(string.encode('utf-8')).decode('utf-8')
83
+ return base64.b64encode(string.encode("utf-8")).decode("utf-8")
65
84
 
66
- def B64Decode(string):
85
+
86
+ def B64Decode(string: TypeString) -> TypeString:
67
87
  if isinstance(string, (FieldMessage, Value)):
68
88
  if not string:
69
89
  return string
70
90
  string = str(string)
71
- return base64.b64decode(string.encode('utf-8')).decode('utf-8')
91
+ return base64.b64decode(string.encode("utf-8")).decode("utf-8")
92
+
93
+
94
+ class TypeProtobuf:
95
+ def __getattr__(self, key):
96
+ if key not in self.__dict__:
97
+ raise AttributeError(
98
+ f"{self.__class__.__name__} attribute does not exist: {key}"
99
+ )
100
+ return self.__dict__[key]
101
+
102
+ def __getitem__(self, key):
103
+ raise ValueError(f"{self.__class__.__name__} does not have dynamic items")
104
+
105
+ def __iter__(self):
106
+ raise ValueError(f"{self.__class__.__name__} is not iterable")
107
+
108
+ def __int__(self):
109
+ raise ValueError(f"{self.__class__.__name__} is not an integer")
72
110
 
111
+ def __float__(self):
112
+ raise ValueError(f"{self.__class__.__name__} is not a float")
73
113
 
74
- class Message:
75
- def __init__(self, parent, key, descriptor, message=_Unknown, readOnly=False):
76
- self._set_attribute('_parent', parent)
77
- self._set_attribute('_key', key)
78
- self._set_attribute('_descriptor', descriptor)
79
- self._set_attribute('_message', message)
80
- self._set_attribute('_readOnly', readOnly)
81
- self._set_attribute('_cache', {})
114
+ def __call__(self, *args, **kwargs):
115
+ raise ValueError(f"{self.__class__.__name__} is not callable")
82
116
 
83
- def _set_attribute(self, key, value):
117
+ def __setattr__(self, key, value):
84
118
  self.__dict__[key] = value
85
119
 
86
- def __getattr__(self, key):
120
+ def __setitem__(self, key, value):
121
+ raise ValueError(f"{self.__class__.__name__} does not have dynamic items")
122
+
123
+ def __delattr__(self, key):
124
+ raise ValueError(f"{self.__class__.__name__} does not have dynamic attributes")
125
+
126
+ def __delitem__(self, key):
127
+ raise ValueError(f"{self.__class__.__name__} does not have dynamic items")
128
+
129
+ def append(self, value):
130
+ raise ValueError(f"{self.__class__.__name__} does not have dynamic items")
131
+
132
+
133
+ class Message(TypeProtobuf):
134
+ def __init__(
135
+ self,
136
+ parent: Message | MapMessage | RepeatedMessage | None,
137
+ key: str | int | Value | FieldMessage | None,
138
+ descriptor: google.protobuf.descriptor.Descriptor,
139
+ message: google.protobuf.message.Message | _Unknown = _Unknown,
140
+ readOnly: str | bool = False,
141
+ ):
142
+ self._parent: Message | MapMessage | RepeatedMessage | None = parent
143
+ self._key = key
144
+ self._descriptor: google.protobuf.descriptor.Descriptor = descriptor
145
+ self._message: google.protobuf.message.Message | _Unknown = message
146
+ self._readOnly: str | bool = readOnly
147
+ self._cache: dict[str, typing.Any] = {}
148
+
149
+ def _ensure_message(self):
150
+ if self._message is _Unknown:
151
+ if self._parent is None:
152
+ raise ValueError(
153
+ "Messages does not have parent to create internal message"
154
+ )
155
+ self._message: google.protobuf.message.Message = self._parent._create_child(
156
+ self._key
157
+ )
158
+
159
+ def __getattr__(
160
+ self, key
161
+ ) -> Message | MapMessage | RepeatedMessage | FieldMessage | Value:
87
162
  return self[key]
88
163
 
89
- def __getitem__(self, key):
164
+ def __getitem__(
165
+ self, key
166
+ ) -> Message | MapMessage | RepeatedMessage | FieldMessage | Value:
90
167
  key = self._validate_key(key)
91
168
  if key in self._cache:
92
169
  return self._cache[key]
93
170
  field = self._descriptor.fields_by_name.get(key)
94
- if not field:
171
+ if field is None:
95
172
  raise AttributeError(obj=self, name=key)
96
173
  if self._message is _Unknown:
97
174
  value = _Unknown
@@ -100,12 +177,22 @@ class Message:
100
177
  if value is _Unknown and field.has_default_value:
101
178
  value = field.default_value
102
179
  if field.is_repeated:
103
- if field.type == field.TYPE_MESSAGE and field.message_type.GetOptions().map_entry:
104
- value = MapMessage(self, key, field.message_type.fields_by_name['value'], value, self._readOnly)
180
+ if (
181
+ field.type == field.TYPE_MESSAGE
182
+ and field.message_type
183
+ and field.message_type.GetOptions().map_entry
184
+ ):
185
+ value = MapMessage(
186
+ self,
187
+ key,
188
+ field.message_type.fields_by_name["value"],
189
+ value,
190
+ self._readOnly,
191
+ )
105
192
  else:
106
193
  value = RepeatedMessage(self, key, field, value, self._readOnly)
107
- elif field.type == field.TYPE_MESSAGE:
108
- if field.message_type.name in ('Struct', 'ListValue'):
194
+ elif field.type == field.TYPE_MESSAGE and field.message_type:
195
+ if field.message_type.name in ("Struct", "ListValue"):
109
196
  value = Value(self, key, value, self._readOnly)
110
197
  else:
111
198
  value = Message(self, key, field.message_type, value, self._readOnly)
@@ -129,7 +216,11 @@ class Message:
129
216
 
130
217
  def __hash__(self):
131
218
  if self._message is not _Unknown:
132
- return hash(tuple(hash(item) for item in sorted(iter(self), key=lambda item: item[0])))
219
+ return hash(
220
+ tuple(
221
+ hash(item) for item in sorted(iter(self), key=lambda item: item[0])
222
+ )
223
+ )
133
224
  return 0
134
225
 
135
226
  def __eq__(self, other):
@@ -153,7 +244,7 @@ class Message:
153
244
  def __str__(self):
154
245
  return format(self)
155
246
 
156
- def __format__(self, spec='yaml'):
247
+ def __format__(self, spec="yaml"):
157
248
  return _formatObject(self, spec)
158
249
 
159
250
  def _fullName(self, key=None):
@@ -163,36 +254,37 @@ class Message:
163
254
  else:
164
255
  name = str(self._key)
165
256
  if key is not None:
166
- if '.' in key:
257
+ if "." in key:
167
258
  name += f"[{key}]"
168
259
  else:
169
260
  name += f".{key}"
170
261
  return name
171
262
  if key is not None:
172
263
  return str(key)
173
- return ''
264
+ return ""
174
265
 
175
266
  def _create_child(self, key):
176
267
  if self._readOnly:
177
268
  raise ValueError(f"{self._readOnly} is read only")
178
269
  key = self._validate_key(key)
179
- if self._message is _Unknown:
180
- self.__dict__['_message'] = self._parent._create_child(self._key)
270
+ self._ensure_message()
181
271
  return getattr(self._message, key)
182
272
 
183
273
  def __call__(self, **kwargs):
184
274
  if self._readOnly:
185
275
  raise ValueError(f"{self._readOnly} is read only")
186
- if self._message is _Unknown:
187
- self.__dict__['_message'] = self._parent._create_child(self._key)
188
- self._message.Clear()
276
+ self._ensure_message()
277
+ typing.cast(google.protobuf.message.Message, self._message).Clear()
189
278
  self._cache.clear()
190
279
  for key, value in kwargs.items():
191
280
  self[key] = value
192
281
  return self
193
282
 
194
283
  def __setattr__(self, key, value):
195
- self[key] = value
284
+ if key in ("_parent", "_key", "_descriptor", "_message", "_readOnly", "_cache"):
285
+ self.__dict__[key] = value
286
+ else:
287
+ self[key] = value
196
288
 
197
289
  def __setitem__(self, key, value):
198
290
  if self._readOnly:
@@ -200,19 +292,34 @@ class Message:
200
292
  key = self._validate_key(key)
201
293
  if key not in self._descriptor.fields_by_name:
202
294
  raise AttributeError(obj=self, name=key)
203
- field = self._descriptor.fields_by_name[key]
204
- if self._message is _Unknown:
205
- self.__dict__['_message'] = self._parent._create_child(self._key)
206
- if isinstance(value, Message):
207
- value = value._message
208
- elif isinstance(value, (MapMessage, RepeatedMessage)):
209
- value = value._messages
210
- elif isinstance(value, FieldMessage):
295
+ if isinstance(value, (Message, MapMessage)):
296
+ for k, v in value:
297
+ self[key][k] = v
298
+ return
299
+ if isinstance(value, dict):
300
+ for k, v in value.items():
301
+ self[key][k] = v
302
+ return
303
+ if isinstance(value, (RepeatedMessage, list, tuple)):
304
+ for ix, v in enumerate(value):
305
+ self[key][ix] = v
306
+ return
307
+ if isinstance(value, FieldMessage):
211
308
  value = value._value
212
309
  elif isinstance(value, Value):
310
+ if value._isMap:
311
+ for k, v in value:
312
+ self[key][k] = v
313
+ return
314
+ if value._isList:
315
+ for ix, v in enumerate(value):
316
+ self[key][ix] = v
317
+ return
213
318
  value = value._raw
319
+ field = self._descriptor.fields_by_name[key]
214
320
  if field.type == field.TYPE_BYTES and isinstance(value, str):
215
- value = value.encode('utf-8')
321
+ value = value.encode("utf-8")
322
+ self._ensure_message()
216
323
  setattr(self._message, key, value)
217
324
  self._cache.pop(key, None)
218
325
 
@@ -239,17 +346,21 @@ class Message:
239
346
  return key
240
347
 
241
348
 
242
- class MapMessage:
243
- def __init__(self, parent, key, field, messages=_Unknown, readOnly=False):
244
- self._set_attribute('_parent', parent)
245
- self._set_attribute('_key', key)
246
- self._set_attribute('_field', field)
247
- self._set_attribute('_messages', messages)
248
- self._set_attribute('_readOnly', readOnly)
249
- self._set_attribute('_cache', {})
250
-
251
- def _set_attribute(self, key, value):
252
- self.__dict__[key] = value
349
+ class MapMessage(TypeProtobuf):
350
+ def __init__(
351
+ self,
352
+ parent: Message,
353
+ key: str,
354
+ field: google.protobuf.descriptor.FieldDescriptor,
355
+ messages: ScalarMap | MessageMap | _Unknown = _Unknown,
356
+ readOnly: str | bool = False,
357
+ ):
358
+ self._parent: Message = parent
359
+ self._key: str = key
360
+ self._field: google.protobuf.descriptor.FieldDescriptor = field
361
+ self._messages: ScalarMap | MessageMap | _Unknown = messages
362
+ self._readOnly = readOnly
363
+ self._cache: dict[str, typing.Any] = {}
253
364
 
254
365
  def __getattr__(self, key):
255
366
  return self[key]
@@ -264,11 +375,13 @@ class MapMessage:
264
375
  value = self._messages[key]
265
376
  if value is None and self._field.has_default_value:
266
377
  value = self._field.default_value
267
- if self._field.type == self._field.TYPE_MESSAGE:
268
- if self._field.message_type.name in ('Struct', 'ListValue'):
378
+ if self._field.type == self._field.TYPE_MESSAGE and self._field.message_type:
379
+ if str(self._field.message_type.name) in ("Struct", "ListValue"):
269
380
  value = Value(self, key, value, self._readOnly)
270
381
  else:
271
- value = Message(self, key, self._field.message_type, value, self._readOnly)
382
+ value = Message(
383
+ self, key, self._field.message_type, value, self._readOnly
384
+ )
272
385
  else:
273
386
  value = FieldMessage(self, key, self._field.type, value)
274
387
  self._cache[key] = value
@@ -281,7 +394,9 @@ class MapMessage:
281
394
  return 0 if self._messages is _Unknown else len(self._messages)
282
395
 
283
396
  def __contains__(self, key):
284
- return self._messages is not _Unknown and key in self._messages
397
+ return (
398
+ self._messages is not _Unknown and self._validate_key(key) in self._messages
399
+ )
285
400
 
286
401
  def __iter__(self):
287
402
  if self._messages is not _Unknown:
@@ -289,8 +404,12 @@ class MapMessage:
289
404
  yield key, self[key]
290
405
 
291
406
  def __hash__(self):
292
- if self._nessages is not None:
293
- return hash(tuple(hash(item) for item in sorted(iter(self), key=lambda item: item[0])))
407
+ if self._messages is not _Unknown:
408
+ return hash(
409
+ tuple(
410
+ hash(item) for item in sorted(iter(self), key=lambda item: item[0])
411
+ )
412
+ )
294
413
  return 0
295
414
 
296
415
  def __eq__(self, other):
@@ -298,9 +417,13 @@ class MapMessage:
298
417
  return False
299
418
  if self._field.type != other._field.type:
300
419
  return False
301
- if self._field.type == self._field.TYPE_MESSAGE:
302
- if self._field.message_type.full_name != other._field.message_type.full_name:
303
- return False
420
+ if (
421
+ self._field.type == self._field.TYPE_MESSAGE
422
+ and self._field.message_type
423
+ and self._field.message_type.full_name
424
+ != other._field.message_type.full_name
425
+ ):
426
+ return False
304
427
  if self._messages is _Unknown:
305
428
  return other._messages is _Unknown
306
429
  elif other._messages is _Unknown:
@@ -317,67 +440,67 @@ class MapMessage:
317
440
  def __str__(self):
318
441
  return format(self)
319
442
 
320
- def __format__(self, spec='yaml'):
443
+ def __format__(self, spec="yaml"):
321
444
  return _formatObject(self, spec)
322
445
 
323
446
  def _fullName(self, key=None):
324
- if self._key is not None:
325
- if self._parent is not None:
326
- name = self._parent._fullName(self._key)
327
- else:
328
- name = str(self._key)
329
- if key is not None:
330
- if '.' in key:
331
- name += f"[{key}]"
332
- else:
333
- name += f".{key}"
334
- return name
447
+ name = self._parent._fullName(self._key)
335
448
  if key is not None:
336
- return str(key)
337
- return ''
449
+ if "." in key:
450
+ name += f"[{key}]"
451
+ else:
452
+ name += f".{key}"
453
+ return name
338
454
 
339
455
  def _create_child(self, key):
340
456
  if self._readOnly:
341
457
  raise ValueError(f"{self._readOnly} is read only")
342
458
  key = self._validate_key(key)
343
459
  if self._messages is _Unknown:
344
- self.__dict__['_messages'] = self._parent._create_child(self._key)
460
+ self._messages = self._parent._create_child(self._key)
345
461
  return self._messages[key]
346
462
 
347
463
  def __call__(self, **kwargs):
348
464
  if self._readOnly:
349
465
  raise ValueError(f"{self._readOnly} is read only")
350
466
  if self._messages is _Unknown:
351
- self.__dict__['_messages'] = self._parent._create_child(self._key)
467
+ self._messages: ScalarMap | MessageMap = self._parent._create_child(
468
+ self._key
469
+ )
352
470
  self._messages.clear()
353
471
  self._cache.clear()
354
472
  for key, value in kwargs.items():
355
473
  self[key] = value
356
474
  return self
357
475
 
358
- def __setattr__(self, key, message):
359
- self[key] = message
476
+ def __setattr__(self, key, value):
477
+ if key in ("_parent", "_key", "_field", "_messages", "_readOnly", "_cache"):
478
+ self.__dict__[key] = value
479
+ else:
480
+ self[key] = value
360
481
 
361
- def __setitem__(self, key, message):
482
+ def __setitem__(self, key, value):
362
483
  if self._readOnly:
363
484
  raise ValueError(f"{self._readOnly} is read only")
364
485
  key = self._validate_key(key)
365
486
  if self._messages is _Unknown:
366
- self._messages = self._parent._create_child(self._key)
367
- if isinstance(message, Message):
368
- message = message._message
369
- elif isinstance(message, (MapMessage, RepeatedMessage)):
370
- message = message._messages
371
- elif isinstance(message, FieldMessage):
372
- message = message._value
373
- elif isinstance(message, Value):
374
- message = message._raw
375
- if message is _Unknown:
487
+ self._messages: ScalarMap | MessageMap = self._parent._create_child(
488
+ self._key
489
+ )
490
+ if isinstance(value, Message):
491
+ value = value._message
492
+ elif isinstance(value, (MapMessage, RepeatedMessage)):
493
+ value = value._messages
494
+ elif isinstance(value, FieldMessage):
495
+ value = value._value
496
+ elif isinstance(value, Value):
497
+ value = value._raw
498
+ if value is _Unknown:
376
499
  self._messages.pop(key, None)
377
500
  else:
378
- if self._field.type == self._field.TYPE_BYTES and isinstance(message, str):
379
- message = message.encode('utf-8')
380
- self._messages[key] = message
501
+ if self._field.type == self._field.TYPE_BYTES and isinstance(value, str):
502
+ value = value.encode("utf-8")
503
+ self._messages[key] = value
381
504
  self._cache.pop(key, None)
382
505
 
383
506
  def __delattr__(self, key):
@@ -402,14 +525,25 @@ class MapMessage:
402
525
  return key
403
526
 
404
527
 
405
- class RepeatedMessage:
406
- def __init__(self, parent, key, field, messages=_Unknown, readOnly=False):
407
- self._parent = parent
408
- self._key = key
409
- self._field = field
410
- self._messages = messages
411
- self._readOnly = readOnly
412
- self._cache = {}
528
+ class RepeatedMessage(TypeProtobuf):
529
+ def __init__(
530
+ self,
531
+ parent: Message,
532
+ key: str,
533
+ field: google.protobuf.descriptor.FieldDescriptor,
534
+ messages: RepeatedCompositeFieldContainer
535
+ | RepeatedScalarFieldContainer
536
+ | _Unknown = _Unknown,
537
+ readOnly: str | bool = False,
538
+ ):
539
+ self._parent: Message = parent
540
+ self._key: str = key
541
+ self._field: google.protobuf.descriptor.FieldDescriptor = field
542
+ self._messages: (
543
+ RepeatedCompositeFieldContainer | RepeatedScalarFieldContainer | _Unknown
544
+ ) = messages
545
+ self._readOnly: str | bool = readOnly
546
+ self._cache: dict[int, typing.Any] = {}
413
547
 
414
548
  def __getitem__(self, key):
415
549
  key = self._validate_key(key)
@@ -425,8 +559,7 @@ class RepeatedMessage:
425
559
  key = 0
426
560
  else:
427
561
  key = len(self._messages) + key
428
- if key < 0:
429
- key = 0
562
+ key = max(key, 0)
430
563
  if key in self._cache:
431
564
  return self._cache[key]
432
565
  if self._messages is _Unknown or key >= len(self._messages):
@@ -435,11 +568,13 @@ class RepeatedMessage:
435
568
  value = self._messages[key]
436
569
  if value is None and self._field.has_default_value:
437
570
  value = self._field.default_value
438
- if self._field.type == self._field.TYPE_MESSAGE:
439
- if self._field.message_type.name in ('Struct', 'ListValue'):
571
+ if self._field.type == self._field.TYPE_MESSAGE and self._field.message_type:
572
+ if self._field.message_type.name in ("Struct", "ListValue"):
440
573
  value = Value(self, key, value, self._readOnly)
441
574
  else:
442
- value = Message(self, key, self._field.message_type, value, self._readOnly)
575
+ value = Message(
576
+ self, key, self._field.message_type, value, self._readOnly
577
+ )
443
578
  else:
444
579
  value = FieldMessage(self, key, self._field.type, value)
445
580
  self._cache[key] = value
@@ -473,9 +608,13 @@ class RepeatedMessage:
473
608
  return False
474
609
  if self._field.type != other._field.type:
475
610
  return False
476
- if self._field.type == self._field.TYPE_MESSAGE:
477
- if self._field.message_type.full_name != other._field.message_type.full_name:
478
- return False
611
+ if (
612
+ self._field.type == self._field.TYPE_MESSAGE
613
+ and self._field.message_type
614
+ and self._field.message_type.full_name
615
+ != other._field.message_type.full_name
616
+ ):
617
+ return False
479
618
  if self._messages is _Unknown:
480
619
  return other._messages is _Unknown
481
620
  elif other._messages is _Unknown:
@@ -490,7 +629,7 @@ class RepeatedMessage:
490
629
  def __str__(self):
491
630
  return format(self)
492
631
 
493
- def __format__(self, spec='yaml'):
632
+ def __format__(self, spec="yaml"):
494
633
  return _formatObject(self, spec)
495
634
 
496
635
  def _fullName(self, key=None):
@@ -504,34 +643,38 @@ class RepeatedMessage:
504
643
  return name
505
644
  if key is not None:
506
645
  return str(key)
507
- return ''
646
+ return ""
508
647
 
509
648
  def _create_child(self, key):
510
649
  if self._readOnly:
511
650
  raise ValueError(f"{self._readOnly} is read only")
512
651
  key = self._validate_key(key)
513
652
  if self._messages is _Unknown:
514
- self.__dict__['_messages'] = self._parent._create_child(self._key)
653
+ self._messages: (
654
+ RepeatedCompositeFieldContainer | RepeatedScalarFieldContainer
655
+ ) = self._parent._create_child(self._key)
515
656
  if key == append:
516
657
  key = len(self._messages)
517
658
  elif key < 0:
518
659
  key = len(self._messages) + key
519
660
  while key >= len(self._messages):
520
- self._messages.add()
661
+ typing.cast(RepeatedCompositeFieldContainer, self._messages).add()
521
662
  return self._messages[key]
522
663
 
523
664
  def __call__(self, *args):
524
665
  if self._readOnly:
525
666
  raise ValueError(f"{self._readOnly} is read only")
526
667
  if self._messages is _Unknown:
527
- self.__dict__['_messages'] = self._parent._create_child(self._key)
668
+ self._messages: (
669
+ RepeatedCompositeFieldContainer | RepeatedScalarFieldContainer
670
+ ) = self._parent._create_child(self._key)
528
671
  self._messages.clear()
529
672
  self._cache.clear()
530
673
  for arg in args:
531
674
  self.append(arg)
532
675
  return self
533
676
 
534
- def __setitem__(self, key, message):
677
+ def __setitem__(self, key, value):
535
678
  if self._readOnly:
536
679
  raise ValueError(f"{self._readOnly} is read only")
537
680
  key = self._validate_key(key)
@@ -539,25 +682,25 @@ class RepeatedMessage:
539
682
  self._messages = self._parent._create_child(self._key)
540
683
  if key < 0:
541
684
  key = len(self._messages) + key
542
- if isinstance(message, Message):
543
- message = message._message
544
- elif isinstance(message, (MapMessage, RepeatedMessage)):
545
- message = message._messages
546
- elif isinstance(message, FieldMessage):
547
- message = message._value
548
- elif isinstance(message, Value):
549
- message = message._raw
550
- if message is _Unknown:
685
+ if isinstance(value, Message):
686
+ value = value._message
687
+ elif isinstance(value, (MapMessage, RepeatedMessage)):
688
+ value = value._messages
689
+ elif isinstance(value, FieldMessage):
690
+ value = value._value
691
+ elif isinstance(value, Value):
692
+ value = value._raw
693
+ if value is _Unknown:
551
694
  if key < len(self._messages):
552
695
  self._messages.pop(key)
553
696
  self._cache.clear()
554
697
  else:
555
- if self._field.type == self._field.TYPE_BYTES and isinstance(message, str):
556
- message = message.encode('utf-8')
698
+ if self._field.type == self._field.TYPE_BYTES and isinstance(value, str):
699
+ value = value.encode("utf-8")
557
700
  if key >= len(self._messages):
558
- self._messages.append(message)
701
+ self._messages.append(value)
559
702
  else:
560
- self._messages[key] = message
703
+ self._messages[key] = value
561
704
  self._cache.pop(key, None)
562
705
 
563
706
  def __delitem__(self, key):
@@ -568,15 +711,27 @@ class RepeatedMessage:
568
711
  del self._messages[key]
569
712
  self._cache.pop(key, None)
570
713
 
571
- def append(self, message=_Unknown):
714
+ def append(self, value=_Unknown) -> TypeProtobuf:
572
715
  if self._readOnly:
573
716
  raise ValueError(f"{self._readOnly} is read only")
574
717
  if self._messages is _Unknown:
575
- self._messages = self._parent._create_child(self._key)
576
- if message is _Unknown:
577
- message = self._messages.add()
718
+ self._messages: RepeatedCompositeFieldContainer = (
719
+ self._parent._create_child(self._key)
720
+ )
721
+ if isinstance(value, Message):
722
+ value = value._message
723
+ elif isinstance(value, (MapMessage, RepeatedMessage)):
724
+ value = value._messages
725
+ elif isinstance(value, FieldMessage):
726
+ value = value._value
727
+ elif isinstance(value, Value):
728
+ value = value._raw
729
+ if value is _Unknown:
730
+ typing.cast(RepeatedCompositeFieldContainer, self._messages).add()
578
731
  else:
579
- message = self._messages.append(message)
732
+ if self._field.type == self._field.TYPE_BYTES and isinstance(value, str):
733
+ value = value.encode("utf-8")
734
+ self._messages.append(value)
580
735
  return self[len(self._messages) - 1]
581
736
 
582
737
  def _validate_key(self, key):
@@ -589,23 +744,29 @@ class RepeatedMessage:
589
744
  return key
590
745
 
591
746
 
592
- class FieldMessage:
593
- def __init__(self, parent, key, kind, value):
594
- self._parent = parent
595
- self._key = key
596
- self._kind = kind
597
- self._value = value
747
+ class FieldMessage(TypeProtobuf):
748
+ def __init__(
749
+ self,
750
+ parent: Message | MapMessage | RepeatedMessage,
751
+ key: str | int,
752
+ kind: int,
753
+ value: typing.Any,
754
+ ):
755
+ self._parent: Message | MapMessage | RepeatedMessage = parent
756
+ self._key: str | int = key
757
+ self._kind: int = kind
758
+ self._value: typing.Any = value
598
759
 
599
760
  def __bool__(self):
600
761
  return self._value is not _Unknown
601
762
 
602
763
  def __len__(self):
603
- if self._value is _Unknown:
764
+ if self._value is _Unknown or not isinstance(self._value, (bytes, str)):
604
765
  return 0
605
766
  return len(self._value)
606
767
 
607
768
  def __contains__(self, key):
608
- if self._value is _Unknown:
769
+ if self._value is _Unknown or not isinstance(self._value, (bytes, str)):
609
770
  return False
610
771
  return key in self._value
611
772
 
@@ -618,24 +779,29 @@ class FieldMessage:
618
779
  if self._value is _Unknown:
619
780
  return False
620
781
  if isinstance(other, FieldMessage):
621
- return self._value == other._value
782
+ other = other._value
783
+ if isinstance(self._value, str):
784
+ if isinstance(other, bytes):
785
+ other = other.decode("utf-8")
786
+ elif isinstance(self._value, bytes) and isinstance(other, str):
787
+ other = other.encode("utf-8")
622
788
  return self._value == other
623
789
 
624
790
  def __bytes__(self):
625
- if self._value is _Unknown:
626
- return None
791
+ if self._value is _Unknown or not isinstance(self._value, (bytes, str)):
792
+ return None # noqa: PLE0308
627
793
  if isinstance(self._value, str):
628
- return self._value.encode('utf-8')
794
+ return self._value.encode("utf-8")
629
795
  return bytes(self._value)
630
796
 
631
797
  def __str__(self):
632
798
  if self._value is _Unknown:
633
- return None
799
+ return None # noqa: PLE0307
634
800
  if isinstance(self._value, bytes):
635
- return self._value.decode('utf-8')
801
+ return self._value.decode("utf-8")
636
802
  return str(self._value)
637
803
 
638
- def __format__(self, spec=''):
804
+ def __format__(self, spec=""):
639
805
  if self._value is _Unknown:
640
806
  return None
641
807
  return format(self._value, spec)
@@ -651,20 +817,13 @@ class FieldMessage:
651
817
  return float(self._value)
652
818
 
653
819
  def _fullName(self, key=None):
654
- if self._key is not None:
655
- if self._parent is not None:
656
- name = self._parent._fullName(self._key)
657
- else:
658
- name = str(self._key)
659
- if key is not None:
660
- if '.' in key:
661
- name += f"[{key}]"
662
- else:
663
- name += f".{key}"
664
- return name
820
+ name = self._parent._fullName(self._key)
665
821
  if key is not None:
666
- return str(key)
667
- return ''
822
+ if "." in key:
823
+ name += f"[{key}]"
824
+ else:
825
+ name += f".{key}"
826
+ return name
668
827
 
669
828
 
670
829
  class ProtobufValue:
@@ -673,20 +832,38 @@ class ProtobufValue:
673
832
  return None
674
833
 
675
834
 
676
- class Value:
677
- def __init__(self, parent, key, value=_Unknown, readOnly=None):
678
- self._set_attribute('_parent', parent)
679
- self._set_attribute('_key', key)
680
- self._set_attribute('_dependencies', {})
681
- self._set_attribute('_unknowns', {})
682
- self._set_attribute('_cache', {})
683
- self._set_attribute('_readOnly', None)
684
- if isinstance(value, (google.protobuf.struct_pb2.Value, google.protobuf.struct_pb2.Struct, google.protobuf.struct_pb2.ListValue)) or value is _Unknown:
685
- self._set_attribute('_value', value)
835
+ class Value(TypeProtobuf):
836
+ def __init__(
837
+ self,
838
+ parent: Message | MapMessage | RepeatedMessage | Value | None,
839
+ key: str | int | None,
840
+ value: typing.Any | _Unknown = _Unknown,
841
+ readOnly: str | bool = False,
842
+ ):
843
+ self._parent: Message | MapMessage | RepeatedMessage | Value | None = parent
844
+ self._key: str | int | None = key
845
+ self._dependencies: dict[str | int, FieldMessage | Value] = {}
846
+ self._unknowns: dict[str | int, FieldMessage | Value] = {}
847
+ self._cache: dict[str | int, Value] = {}
848
+ self._readOnly: str | bool = False
849
+ if (
850
+ isinstance(
851
+ value,
852
+ (
853
+ google.protobuf.struct_pb2.Value,
854
+ google.protobuf.struct_pb2.Struct,
855
+ google.protobuf.struct_pb2.ListValue,
856
+ ),
857
+ )
858
+ or value is _Unknown
859
+ ):
860
+ self._value: typing.Any = value
686
861
  else:
687
- self._set_attribute('_value', google.protobuf.struct_pb2.Value())
862
+ self._value: google.protobuf.struct_pb2.Value = (
863
+ google.protobuf.struct_pb2.Value()
864
+ )
688
865
  if value is None:
689
- self._value.null_value = 0
866
+ self._value.null_value = google.protobuf.struct_pb2.NULL_VALUE
690
867
  elif isinstance(value, dict):
691
868
  self._value.struct_value.Clear()
692
869
  for k, v in value.items():
@@ -695,7 +872,7 @@ class Value:
695
872
  self._value.list_value.Clear()
696
873
  for ix, v in enumerate(value):
697
874
  self[ix] = v
698
- elif isinstance(value, bool): # Must be before number check
875
+ elif isinstance(value, bool): # Must be before number check
699
876
  self._value.bool_value = value
700
877
  elif isinstance(value, (int, float)):
701
878
  self._value.number_value = value
@@ -703,10 +880,7 @@ class Value:
703
880
  self._value.string_value = value
704
881
  else:
705
882
  raise ValueError(f"Unexpected Value type: {value.__class__}")
706
- self._set_attribute('_readOnly', readOnly)
707
-
708
- def _set_attribute(self, key, value):
709
- self.__dict__[key] = value
883
+ self._setReadOnly(readOnly)
710
884
 
711
885
  def __enter__(self):
712
886
  return self
@@ -714,12 +888,6 @@ class Value:
714
888
  def __exit__(self, exc_type, exc_value, traceback):
715
889
  pass
716
890
 
717
- def __aenter__(self):
718
- return self
719
-
720
- def __aexit__(self, exc_type, exc_value, traceback):
721
- pass
722
-
723
891
  def __getattr__(self, key):
724
892
  return self[key]
725
893
 
@@ -732,42 +900,40 @@ class Value:
732
900
  return self._unknowns[key]
733
901
  if isinstance(key, str):
734
902
  match self._kind:
735
- case 'struct_value':
903
+ case "struct_value":
736
904
  value = self._value.struct_value.fields.get(key, _Unknown)
737
- case 'Struct':
905
+ case "Struct":
738
906
  value = self._value.fields.get(key, _Unknown)
739
- case 'Unknown':
907
+ case "Unknown":
740
908
  value = _Unknown
741
909
  case _:
742
- raise ValueError(f"Invalid key \"{key}\" for kind: {self._kind}")
910
+ raise ValueError(f'Invalid key "{key}" for kind: {self._kind}')
743
911
  elif isinstance(key, int):
744
912
  match self._kind:
745
- case 'list_value':
913
+ case "list_value":
746
914
  if key < 0:
747
915
  key = len(self._value.list_value.values) + key
748
- if key < 0:
749
- key = 0
916
+ key = max(key, 0)
750
917
  if key < len(self._value.list_value.values):
751
918
  value = self._value.list_value.values[key]
752
919
  else:
753
920
  if key == append:
754
921
  key = len(self._value.list_value.values)
755
922
  value = _Unknown
756
- case 'ListValue':
923
+ case "ListValue":
757
924
  if key < 0:
758
925
  key = len(self._value.values) + key
759
- if key < 0:
760
- key = 0
926
+ key = max(key, 0)
761
927
  if key < len(self._value.values):
762
928
  value = self._value.values[key]
763
929
  else:
764
930
  if key == append:
765
931
  key = len(self._value.values)
766
932
  value = _Unknown
767
- case 'Unknown':
933
+ case "Unknown":
768
934
  value = _Unknown
769
935
  case _:
770
- raise ValueError(f"Invalid key \"{key}\" for kind: {self._kind}")
936
+ raise ValueError(f'Invalid key "{key}" for kind: {self._kind}')
771
937
  else:
772
938
  raise NotImplementedError()
773
939
  value = Value(self, key, value, self._readOnly)
@@ -779,29 +945,29 @@ class Value:
779
945
 
780
946
  def __len__(self):
781
947
  match self._kind:
782
- case 'struct_value':
948
+ case "struct_value":
783
949
  return len(self._value.struct_value.fields) + len(self._unknowns)
784
- case 'Struct':
950
+ case "Struct":
785
951
  return len(self._value.fields) + len(self._unknowns)
786
- case 'list_value':
952
+ case "list_value":
787
953
  return len(self._value.list_value.values) + len(self._unknowns)
788
- case 'ListValue':
954
+ case "ListValue":
789
955
  return len(self._value.values) + len(self._unknowns)
790
- case 'string_value':
956
+ case "string_value":
791
957
  return len(self._value.string_value)
792
- case 'bool_value':
958
+ case "bool_value":
793
959
  return 1 if self._value.bool_value else 0
794
960
  return 0
795
961
 
796
962
  def __contains__(self, item):
797
963
  match self._kind:
798
- case 'struct_value':
964
+ case "struct_value":
799
965
  item = self._validate_key(item)
800
966
  return item in self._value.struct_value.fields or item in self._unknowns
801
- case 'Struct':
967
+ case "Struct":
802
968
  item = self._validate_key(item)
803
969
  return item in self._value.fields or item in self._unknowns
804
- case 'list_value' | 'ListValue':
970
+ case "list_value" | "ListValue":
805
971
  for value in self:
806
972
  if item == value:
807
973
  return True
@@ -809,38 +975,45 @@ class Value:
809
975
 
810
976
  def __iter__(self):
811
977
  match self._kind:
812
- case 'struct_value':
813
- for key in sorted(set(self._value.struct_value.fields) | set(self._unknowns.keys())):
978
+ case "struct_value":
979
+ for key in sorted(
980
+ set(self._value.struct_value.fields) | set(self._unknowns.keys())
981
+ ):
814
982
  yield key, self[key]
815
- case 'Struct':
983
+ case "Struct":
816
984
  for key in sorted(set(self._value.fields) | set(self._unknowns.keys())):
817
985
  yield key, self[key]
818
- case 'list_value':
986
+ case "list_value":
819
987
  for ix in range(len(self._value.list_value.values)):
820
988
  yield self[ix]
821
989
  for ix in sorted(self._unknowns.keys()):
822
- if ix >= len(self._value.list_value.values):
990
+ if typing.cast(int, ix) >= len(self._value.list_value.values):
823
991
  yield self[ix]
824
- case 'ListValue':
992
+ case "ListValue":
825
993
  for ix in range(len(self._value.values)):
826
994
  yield self[ix]
827
995
  for ix in sorted(self._unknowns.keys()):
828
- if ix >= len(self._value.values):
996
+ if typing.cast(int, ix) >= len(self._value.values):
829
997
  yield self[ix]
830
998
 
831
999
  def __hash__(self):
832
1000
  match self._kind:
833
- case 'struct_value' | 'Struct':
834
- return hash(tuple(hash(item) for item in sorted(iter(self), key=lambda item: item[0])))
835
- case 'list_value' | 'ListValue':
1001
+ case "struct_value" | "Struct":
1002
+ return hash(
1003
+ tuple(
1004
+ hash(item)
1005
+ for item in sorted(iter(self), key=lambda item: item[0])
1006
+ )
1007
+ )
1008
+ case "list_value" | "ListValue":
836
1009
  return hash(tuple(hash(item) for item in self))
837
- case 'string_value':
1010
+ case "string_value":
838
1011
  return hash(self._value.string_value)
839
- case 'null_value':
1012
+ case "null_value":
840
1013
  return hash(None)
841
- case 'number_value':
1014
+ case "number_value":
842
1015
  return hash(self._value.number_value)
843
- case 'bool_value':
1016
+ case "bool_value":
844
1017
  return hash(self._value.bool_value)
845
1018
  return 0
846
1019
 
@@ -849,7 +1022,7 @@ class Value:
849
1022
  if isinstance(other, Value) and other._kind != kind:
850
1023
  return False
851
1024
  match kind:
852
- case 'struct_value' | 'Struct':
1025
+ case "struct_value" | "Struct":
853
1026
  if not isinstance(other, (Value, dict)):
854
1027
  return False
855
1028
  if len(self) != len(other):
@@ -860,7 +1033,7 @@ class Value:
860
1033
  if value != other[key]:
861
1034
  return False
862
1035
  return True
863
- case 'list_value' | 'ListValue':
1036
+ case "list_value" | "ListValue":
864
1037
  if not isinstance(other, (Value, tuple, list)):
865
1038
  return False
866
1039
  if len(self) != len(other):
@@ -869,27 +1042,27 @@ class Value:
869
1042
  if value != other[ix]:
870
1043
  return False
871
1044
  return True
872
- case 'Unknown':
1045
+ case "Unknown":
873
1046
  if isinstance(other, Value):
874
1047
  return other._isUnknown
875
1048
  return False
876
- case 'string_value':
1049
+ case "string_value":
877
1050
  if isinstance(other, Value):
878
1051
  return self._value.string_value == other._value.string_value
879
1052
  if isinstance(other, str):
880
1053
  return self._value.string_value == other
881
1054
  return False
882
- case 'null_value':
1055
+ case "null_value":
883
1056
  if isinstance(other, Value):
884
1057
  return True
885
1058
  return other is None
886
- case 'number_value':
1059
+ case "number_value":
887
1060
  if isinstance(other, Value):
888
1061
  return self._value.number_value == other._value.number_value
889
1062
  if isinstance(other, (int, float)):
890
1063
  return self._value.number_value == other
891
1064
  return False
892
- case 'bool_value':
1065
+ case "bool_value":
893
1066
  if isinstance(other, Value):
894
1067
  return self._value.bool_value == other._value.bool_value
895
1068
  if isinstance(other, bool):
@@ -899,7 +1072,7 @@ class Value:
899
1072
 
900
1073
  def __or__(self, other):
901
1074
  kind = self._kind
902
- if kind not in ('struct_value', 'Struct'):
1075
+ if kind not in ("struct_value", "Struct"):
903
1076
  return NotImplemented
904
1077
  if not isinstance(other, (Value, dict)):
905
1078
  return NotImplemented
@@ -917,56 +1090,56 @@ class Value:
917
1090
  result = Map()
918
1091
  for key, value in other.items():
919
1092
  result[key] = value
920
- if self._kind not in ('struct_value', 'Struct'):
1093
+ if self._kind not in ("struct_value", "Struct"):
921
1094
  return NotImplemented
922
1095
  for key, value in self:
923
1096
  result[key] = value
924
1097
  return result
925
1098
 
926
1099
  def __str__(self):
927
- return format(self, '')
1100
+ return format(self, "")
928
1101
 
929
- def __format__(self, spec='yaml'):
1102
+ def __format__(self, spec="yaml"):
930
1103
  if not spec:
931
1104
  match self._kind:
932
- case 'Unknown':
933
- return '<<UNKNOWN>>'
934
- case 'string_value':
1105
+ case "Unknown":
1106
+ return "<<UNKNOWN>>"
1107
+ case "string_value":
935
1108
  return self._value.string_value
936
- case 'null_value':
937
- return 'null'
938
- case 'number_value':
1109
+ case "null_value":
1110
+ return "null"
1111
+ case "number_value":
939
1112
  value = self._value.number_value
940
1113
  if value.is_integer():
941
1114
  value = int(value)
942
1115
  return str(value)
943
- case 'bool_value':
944
- return 'true' if self._value.bool_value else 'false'
1116
+ case "bool_value":
1117
+ return "true" if self._value.bool_value else "false"
945
1118
  return _formatObject(self, spec)
946
1119
 
947
1120
  def __int__(self):
948
1121
  kind = self._kind
949
1122
  match kind:
950
- case 'string_value':
1123
+ case "string_value":
951
1124
  return int(self._value.string_value)
952
- case 'number_value':
1125
+ case "number_value":
953
1126
  return int(self._value.number_value)
954
- case 'bool_value':
1127
+ case "bool_value":
955
1128
  return int(self._value.bool_value)
956
- case 'Unknown':
1129
+ case "Unknown":
957
1130
  return 0
958
1131
  raise TypeError(f"Cannot convert kind to integer: {kind}")
959
1132
 
960
1133
  def __float__(self):
961
1134
  kind = self._kind
962
1135
  match kind:
963
- case 'string_value':
1136
+ case "string_value":
964
1137
  return float(self._value.string_value)
965
- case 'number_value':
1138
+ case "number_value":
966
1139
  return float(self._value.number_value)
967
- case 'bool_value':
1140
+ case "bool_value":
968
1141
  return float(self._value.bool_value)
969
- case 'Unknown':
1142
+ case "Unknown":
970
1143
  return 0.0
971
1144
  raise TypeError(f"Cannot convert kind to float: {kind}")
972
1145
 
@@ -988,25 +1161,25 @@ class Value:
988
1161
  if isinstance(key, int):
989
1162
  name += f"[{key}]"
990
1163
  else:
991
- if '.' in key:
1164
+ if "." in key:
992
1165
  name += f"[{key}]"
993
1166
  else:
994
1167
  name += f".{key}"
995
1168
  return name
996
1169
  if key is not None:
997
1170
  return str(key)
998
- return ''
1171
+ return ""
999
1172
 
1000
1173
  def __call__(self, *args, **kwargs):
1001
1174
  if self._readOnly:
1002
1175
  raise ValueError(f"{self._readOnly} is read only")
1003
- self.__dict__['_value'] = google.protobuf.struct_pb2.Value()
1176
+ self.__dict__["_value"] = google.protobuf.struct_pb2.Value()
1004
1177
  self._cache.clear()
1005
1178
  self._dependencies.clear()
1006
1179
  self._unknowns.clear()
1007
1180
  if len(kwargs):
1008
1181
  if len(args):
1009
- raise ValueError('Connect specify both kwargs and args')
1182
+ raise ValueError("Connect specify both kwargs and args")
1010
1183
  for key, value in kwargs.items():
1011
1184
  self[key] = value
1012
1185
  elif len(args):
@@ -1017,19 +1190,30 @@ class Value:
1017
1190
  return self
1018
1191
 
1019
1192
  def __setattr__(self, key, value):
1020
- self[key] = value
1193
+ if key in (
1194
+ "_parent",
1195
+ "_key",
1196
+ "_value",
1197
+ "_dependencies",
1198
+ "_unknowns",
1199
+ "_cache",
1200
+ "_readOnly",
1201
+ ):
1202
+ self.__dict__[key] = value
1203
+ else:
1204
+ self[key] = value
1021
1205
 
1022
1206
  def __setitem__(self, key, value):
1023
1207
  if self._readOnly:
1024
1208
  raise ValueError(f"{self._readOnly} is read only")
1025
1209
  key = self._validate_key(key)
1026
1210
  if isinstance(key, str):
1027
- if self._ensure_map() == 'struct_value':
1211
+ if self._ensure_map() == "struct_value":
1028
1212
  values = self._value.struct_value.fields
1029
1213
  else:
1030
1214
  values = self._value.fields
1031
1215
  elif isinstance(key, int):
1032
- if self._ensure_list() == 'list_value':
1216
+ if self._ensure_list() == "list_value":
1033
1217
  values = self._value.list_value.values
1034
1218
  else:
1035
1219
  values = self._value.values
@@ -1048,10 +1232,10 @@ class Value:
1048
1232
  value = value._protobuf_value
1049
1233
  if value is None:
1050
1234
  values[key].null_value = 0
1051
- elif isinstance(value, bool): # Must be before int check
1235
+ elif isinstance(value, bool): # Must be before int check
1052
1236
  values[key].bool_value = value
1053
1237
  elif isinstance(value, bytes):
1054
- values[key].string_value = value._value.decode('utf-8')
1238
+ values[key].string_value = value.decode("utf-8")
1055
1239
  elif isinstance(value, str):
1056
1240
  values[key].string_value = value
1057
1241
  elif isinstance(value, (int, float)):
@@ -1069,13 +1253,13 @@ class Value:
1069
1253
  if isinstance(value._value, str):
1070
1254
  values[key].string_value = value._value
1071
1255
  elif isinstance(value._value, bytes):
1072
- values[key].string_value = value._value.decode('utf-8')
1256
+ values[key].string_value = value._value.decode("utf-8")
1073
1257
  elif value._value is None:
1074
1258
  values[key].null_value = value._value.null_value
1259
+ elif isinstance(value._value, bool): # Must be before number check
1260
+ values[key].bool_value = value._value
1075
1261
  elif isinstance(value._value, (int, float)):
1076
1262
  values[key].number_value = value._value
1077
- elif isinstance(value._value, bool):
1078
- values[key].bool_value = value._value
1079
1263
  elif value._value is _Unknown:
1080
1264
  self._setUnknown(key, value)
1081
1265
  else:
@@ -1083,23 +1267,23 @@ class Value:
1083
1267
  elif isinstance(value, Value):
1084
1268
  self._dependencies[key] = value
1085
1269
  match value._kind:
1086
- case 'struct_value' | 'Struct':
1270
+ case "struct_value" | "Struct":
1087
1271
  values[key].struct_value.Clear()
1088
1272
  for k, v in value:
1089
1273
  self[key][k] = v
1090
- case 'list_value' | 'ListValue':
1274
+ case "list_value" | "ListValue":
1091
1275
  values[key].list_value.Clear()
1092
1276
  for ix, v in enumerate(value):
1093
1277
  self[key][ix] = v
1094
- case 'string_value':
1278
+ case "string_value":
1095
1279
  values[key].string_value = value._value.string_value
1096
- case 'null_value':
1280
+ case "null_value":
1097
1281
  values[key].null_value = value._value.null_value
1098
- case 'number_value':
1282
+ case "number_value":
1099
1283
  values[key].number_value = value._value.number_value
1100
- case 'bool_value':
1284
+ case "bool_value":
1101
1285
  values[key].bool_value = value._value.bool_value
1102
- case 'Unknown':
1286
+ case "Unknown":
1103
1287
  self._setUnknown(key, value)
1104
1288
  case _:
1105
1289
  raise ValueError(f"Unexpected value kind: {value._kind}")
@@ -1109,41 +1293,43 @@ class Value:
1109
1293
  @property
1110
1294
  def _raw(self):
1111
1295
  match self._kind:
1112
- case 'struct_value':
1296
+ case "struct_value":
1113
1297
  return self._value.struct_value
1114
- case 'list_value':
1298
+ case "list_value":
1115
1299
  return self._value.list_value
1116
- case 'string_value':
1300
+ case "string_value":
1117
1301
  return self._value.string_value
1118
- case 'null_value':
1302
+ case "null_value":
1119
1303
  return self._value.null_value
1120
- case 'number_value':
1304
+ case "number_value":
1305
+ if self._value.number_value.is_integer():
1306
+ return int(self._value.number_value)
1121
1307
  return self._value.number_value
1122
- case 'bool_value':
1308
+ case "bool_value":
1123
1309
  return self._value.bool_value
1124
- case 'Struct' | 'ListValue':
1310
+ case "Struct" | "ListValue":
1125
1311
  return self._value
1126
- case 'Unknown':
1312
+ case "Unknown":
1127
1313
  return _Unknown
1128
1314
 
1129
1315
  def _setUnknown(self, key, value):
1130
1316
  self._dependencies.pop(key, None)
1131
1317
  self._unknowns[key] = value
1132
1318
  match self._kind:
1133
- case 'struct_value':
1319
+ case "struct_value":
1134
1320
  if key in self._value.struct_value.fields:
1135
1321
  del self._value.struct_value[key]
1136
- case 'Struct':
1322
+ case "Struct":
1137
1323
  if key in self._value.fields:
1138
1324
  del self._value[key]
1139
- case 'list_value':
1325
+ case "list_value":
1140
1326
  if key < len(self._value.list_value.values):
1141
1327
  self._value.list_value.values[key].Clear()
1142
1328
  for ix in reversed(range(len(self._value.list_value.values))):
1143
1329
  if ix not in self._unknowns:
1144
1330
  break
1145
1331
  del self._value.list_value[ix]
1146
- case 'ListValue':
1332
+ case "ListValue":
1147
1333
  if key < len(self._value.values):
1148
1334
  self._value.values[key].Clear()
1149
1335
  for ix in reversed(range(len(self._value.values))):
@@ -1158,30 +1344,30 @@ class Value:
1158
1344
  if self._readOnly:
1159
1345
  raise ValueError(f"{self._readOnly} is read only")
1160
1346
  kind = self._kind
1161
- if kind == 'Unknown':
1347
+ if kind == "Unknown":
1162
1348
  return
1163
1349
  key = self._validate_key(key)
1164
1350
  if isinstance(key, str):
1165
1351
  match kind:
1166
- case 'struct_value':
1352
+ case "struct_value":
1167
1353
  if key in self._value.struct_value.fields:
1168
1354
  del self._value.struct_value[key]
1169
- case 'Struct':
1355
+ case "Struct":
1170
1356
  if key in self._value.fields:
1171
1357
  del self._value[key]
1172
1358
  case _:
1173
- raise ValueError(f"Invalid key \"{key}\" for kind: {self._kind}")
1359
+ raise ValueError(f'Invalid key "{key}" for kind: {self._kind}')
1174
1360
  self._cache.pop(key, None)
1175
1361
  self._dependencies.pop(key, None)
1176
1362
  self._unknowns.pop(key, None)
1177
1363
  elif isinstance(key, int):
1178
1364
  match kind:
1179
- case 'list_value':
1365
+ case "list_value":
1180
1366
  values = self._value.list_value
1181
- case 'ListValue':
1367
+ case "ListValue":
1182
1368
  values = self._value
1183
1369
  case _:
1184
- raise ValueError(f"Invalid key \"{key}\" for kind: {self._kind}")
1370
+ raise ValueError(f'Invalid key "{key}" for kind: {self._kind}')
1185
1371
  if key < len(values.values):
1186
1372
  del values[key]
1187
1373
  self._cache.pop(key, None)
@@ -1190,12 +1376,14 @@ class Value:
1190
1376
  for ix in sorted(self._dependencies.keys()):
1191
1377
  if ix > key:
1192
1378
  self._cache.pop(ix, None)
1193
- self._dependencies[ix - 1] = self._dependences[ix]
1379
+ self._dependencies[typing.cast(int, ix) - 1] = self._dependencies[
1380
+ ix
1381
+ ]
1194
1382
  del self._dependencies[ix]
1195
1383
  for ix in sorted(self._unknowns.keys()):
1196
1384
  if ix > key:
1197
1385
  self._cache.pop(ix, None)
1198
- self._unknowns[ix - 1] = self._unknowns[ix]
1386
+ self._unknowns[typing.cast(int, ix) - 1] = self._unknowns[ix]
1199
1387
  del self._unknowns[ix]
1200
1388
  for ix in reversed(range(len(values.values))):
1201
1389
  if ix not in self._unknowns:
@@ -1209,14 +1397,14 @@ class Value:
1209
1397
  raise ValueError(f"{self._readOnly} is read only")
1210
1398
  key = self._validate_key(key)
1211
1399
  if isinstance(key, str):
1212
- if self._ensure_map() == 'struct_value':
1400
+ if self._ensure_map() == "struct_value":
1213
1401
  fields = self._value.struct_value.fields
1214
1402
  else:
1215
1403
  fields = self._value.fields
1216
1404
  fields[key].Clear()
1217
1405
  return fields[key]
1218
1406
  if isinstance(key, int):
1219
- if self._ensure_list() == 'list_value':
1407
+ if self._ensure_list() == "list_value":
1220
1408
  values = self._value.list_value.values
1221
1409
  else:
1222
1410
  values = self._value.values
@@ -1241,55 +1429,61 @@ class Value:
1241
1429
 
1242
1430
  def _ensure_map(self):
1243
1431
  kind = self._kind
1244
- if kind == 'Unknown':
1432
+ if kind == "Unknown":
1245
1433
  if self._parent is None:
1246
- self.__dict__['_value'] = google.protobuf.struct_pb2.Value()
1434
+ self.__dict__["_value"] = google.protobuf.struct_pb2.Value()
1247
1435
  else:
1248
- self.__dict__['_value'] = self._parent._create_child(self._key)
1249
- if isinstance(self._value, google.protobuf.struct_pb2.Value) and self._value.WhichOneof('kind') is None:
1436
+ self.__dict__["_value"] = self._parent._create_child(self._key)
1437
+ if (
1438
+ isinstance(self._value, google.protobuf.struct_pb2.Value)
1439
+ and self._value.WhichOneof("kind") is None
1440
+ ):
1250
1441
  self._value.struct_value.Clear()
1251
1442
  kind = self._kind
1252
- if kind not in ('struct_value', 'Struct'):
1443
+ if kind not in ("struct_value", "Struct"):
1253
1444
  raise ValueError(f"Invalid map kind: {kind}")
1254
1445
  return kind
1255
1446
 
1256
1447
  def _ensure_list(self):
1257
1448
  kind = self._kind
1258
- if kind == 'Unknown':
1449
+ if kind == "Unknown":
1259
1450
  if self._parent is None:
1260
- self.__dict__['_value'] = google.protobuf.struct_pb2.Value()
1451
+ self.__dict__["_value"] = google.protobuf.struct_pb2.Value()
1261
1452
  else:
1262
- self.__dict__['_value'] = self._parent._create_child(self._key)
1263
- if isinstance(self._value, google.protobuf.struct_pb2.Value) and self._value.WhichOneof('kind') is None:
1453
+ self.__dict__["_value"] = self._parent._create_child(self._key)
1454
+ if (
1455
+ isinstance(self._value, google.protobuf.struct_pb2.Value)
1456
+ and self._value.WhichOneof("kind") is None
1457
+ ):
1264
1458
  self._value.list_value.Clear()
1265
1459
  kind = self._kind
1266
- if kind not in ('list_value', 'ListValue'):
1460
+ if kind not in ("list_value", "ListValue"):
1267
1461
  raise ValueError(f"Invalid list kind: {kind}")
1268
1462
  return kind
1269
1463
 
1270
1464
  @property
1271
1465
  def _kind(self):
1272
1466
  if isinstance(self._value, google.protobuf.struct_pb2.Value):
1273
- return self._value.WhichOneof('kind') or 'Unknown'
1467
+ return self._value.WhichOneof("kind") or "Unknown"
1274
1468
  if isinstance(self._value, google.protobuf.struct_pb2.Struct):
1275
- return 'Struct'
1469
+ return "Struct"
1276
1470
  if isinstance(self._value, google.protobuf.struct_pb2.ListValue):
1277
- return 'ListValue'
1471
+ return "ListValue"
1278
1472
  if self._value is _Unknown:
1279
- return 'Unknown'
1473
+ return "Unknown"
1280
1474
  raise ValueError(f"Unexpected value type: {self._value.__class__}")
1281
1475
 
1282
1476
  @property
1283
1477
  def _isUnknown(self):
1284
- return self._kind == 'Unknown'
1478
+ return self._kind == "Unknown"
1285
1479
 
1286
1480
  @property
1287
1481
  def _isMap(self):
1288
- return self._kind in ('struct_value', 'Struct')
1482
+ return self._kind in ("struct_value", "Struct")
1289
1483
 
1290
1484
  @property
1291
1485
  def _isList(self):
1292
- return self._kind in ('list_value', 'ListValue')
1486
+ return self._kind in ("list_value", "ListValue")
1293
1487
 
1294
1488
  @property
1295
1489
  def _getUnknowns(self):
@@ -1307,8 +1501,8 @@ class Value:
1307
1501
  return unknowns
1308
1502
 
1309
1503
  @property
1310
- def _getDependencies(self):
1311
- dependencies = {}
1504
+ def _getDependencies(self) -> dict[str, str]:
1505
+ dependencies: dict[str, str] = {}
1312
1506
  for key, dependency in self._dependencies.items():
1313
1507
  dependencies[self._fullName(key)] = dependency._fullName()
1314
1508
  for key, unknown in self._unknowns.items():
@@ -1323,6 +1517,17 @@ class Value:
1323
1517
  dependencies.update(value._getDependencies)
1324
1518
  return dependencies
1325
1519
 
1520
+ def _setReadOnly(self, readOnly: bool | str):
1521
+ self._readOnly = readOnly
1522
+ if self._isMap:
1523
+ for key, value in self:
1524
+ if isinstance(value, Value):
1525
+ value._setReadOnly(readOnly)
1526
+ elif self._isList:
1527
+ for value in enumerate(self):
1528
+ if isinstance(value, Value):
1529
+ value._setReadOnly(readOnly)
1530
+
1326
1531
  def _patchUnknowns(self, patches):
1327
1532
  for key in list(self._unknowns.keys()):
1328
1533
  self[key] = patches[key]
@@ -1330,13 +1535,21 @@ class Value:
1330
1535
  for key, value in self:
1331
1536
  if isinstance(value, Value) and len(value):
1332
1537
  patch = patches[key]
1333
- if isinstance(patch, Value) and patch._kind == value._kind and len(patch):
1538
+ if (
1539
+ isinstance(patch, Value)
1540
+ and patch._kind == value._kind
1541
+ and len(patch)
1542
+ ):
1334
1543
  value._patchUnknowns(patch)
1335
1544
  elif self._isList:
1336
1545
  for ix, value in enumerate(self):
1337
1546
  if isinstance(value, Value) and len(value):
1338
1547
  patch = patches[ix]
1339
- if isinstance(patch, Value) and patch._kind == value._kind and len(patch):
1548
+ if (
1549
+ isinstance(patch, Value)
1550
+ and patch._kind == value._kind
1551
+ and len(patch)
1552
+ ):
1340
1553
  value._patchUnknowns(patch)
1341
1554
 
1342
1555
  def _renderUnknowns(self, trimFullName):
@@ -1353,13 +1566,13 @@ class Value:
1353
1566
  value._renderUnknowns(trimFullName)
1354
1567
 
1355
1568
 
1356
- def _formatObject(object, spec='yaml'):
1569
+ def _formatObject(object, spec="yaml"):
1357
1570
  match spec:
1358
- case 'json':
1571
+ case "json":
1359
1572
  return json.dumps(object, indent=2, cls=_JSONEncoder)
1360
- case 'jsonc':
1361
- return json.dumps(object, separators=(',', ':'), cls=_JSONEncoder)
1362
- case 'protobuf':
1573
+ case "jsonc":
1574
+ return json.dumps(object, separators=(",", ":"), cls=_JSONEncoder)
1575
+ case "protobuf":
1363
1576
  if isinstance(object, Message):
1364
1577
  return str(object._message)
1365
1578
  if isinstance(object, (MapMessage, RepeatedMessage)):
@@ -1372,94 +1585,98 @@ def _formatObject(object, spec='yaml'):
1372
1585
 
1373
1586
 
1374
1587
  class _JSONEncoder(json.JSONEncoder):
1375
- def default(self, object):
1376
- if isinstance(object, (Message, MapMessage)):
1377
- if object:
1378
- return {key: value for key, value in object}
1588
+ def default(self, o):
1589
+ if isinstance(o, (Message, MapMessage)):
1590
+ if o:
1591
+ return {key: value for key, value in o}
1379
1592
  return None
1380
- if isinstance(object, RepeatedMessage):
1381
- if object:
1382
- return [value for value in object]
1593
+ if isinstance(o, RepeatedMessage):
1594
+ if o:
1595
+ return [value for value in o]
1383
1596
  return None
1384
- if isinstance(object, FieldMessage):
1385
- return object._value
1386
- if isinstance(object, Value):
1387
- match object._kind:
1388
- case 'struct_value' | 'Struc':
1389
- return {key: value for key, value in object}
1390
- case 'list_value' | 'ListValue':
1391
- return [value for value in object]
1392
- case 'string_value':
1393
- return object._value.string_value
1394
- case 'null_value':
1597
+ if isinstance(o, FieldMessage):
1598
+ return o._value
1599
+ if isinstance(o, Value):
1600
+ match o._kind:
1601
+ case "struct_value" | "Struct":
1602
+ return {key: value for key, value in o}
1603
+ case "list_value" | "ListValue":
1604
+ return [value for value in o]
1605
+ case "string_value":
1606
+ return o._value.string_value
1607
+ case "null_value":
1395
1608
  return None
1396
- case 'number_value':
1397
- value = object._value.number_value
1609
+ case "number_value":
1610
+ value = o._value.number_value
1398
1611
  if value.is_integer():
1399
1612
  value = int(value)
1400
1613
  return value
1401
- case 'bool_value':
1402
- return object._value.bool_value
1403
- case 'Unknown':
1404
- return '<<UNKNOWN>>'
1614
+ case "bool_value":
1615
+ return o._value.bool_value
1616
+ case "Unknown":
1617
+ return "<<UNKNOWN>>"
1405
1618
  case _:
1406
- return '<<UNEXPECTED>>'
1407
- if isinstance(object, datetime.datetime):
1408
- return object.isoformat()
1409
- return super(_JSONEncoder, self).default(object)
1619
+ return "<<UNEXPECTED>>"
1620
+ if isinstance(o, datetime.datetime):
1621
+ return o.isoformat()
1622
+ if isinstance(o, bytes):
1623
+ return o.decode("utf-8")
1624
+ return super().default(o)
1410
1625
 
1411
1626
 
1412
1627
  class _Dumper(yaml.SafeDumper):
1413
-
1414
1628
  def represent_str(self, data):
1415
- return self.represent_scalar('tag:yaml.org,2002:str', data, '|' if '\n' in data else None)
1629
+ return self.represent_scalar(
1630
+ "tag:yaml.org,2002:str", data, "|" if "\n" in data else None
1631
+ )
1416
1632
 
1417
- def represent_message_dict(self, message):
1633
+ def represent_message_dict(self, message: Message | MapMessage):
1418
1634
  return self.represent_dict({key: value for key, value in message})
1419
1635
 
1420
- def represent_message_list(self, messages):
1636
+ def represent_message_list(self, messages: RepeatedMessage):
1421
1637
  return self.represent_list([value for value in messages])
1422
1638
 
1423
- def represent_message_field(self, field):
1639
+ def represent_message_field(self, field: FieldMessage):
1424
1640
  if isinstance(field._value, str):
1425
1641
  return self.represent_str(field._value)
1426
1642
  if isinstance(field._value, bytes):
1427
1643
  return self.represent_binary(field._value)
1428
1644
  if field._value is None:
1429
- return self.represent_none()
1645
+ return self.represent_none(field._value)
1646
+ if isinstance(field._value, bool): # Must be before number check
1647
+ return self.represent_bool(bool(field._value))
1430
1648
  if isinstance(field._value, int):
1431
1649
  return self.represent_int(field._value)
1432
1650
  if isinstance(field._value, float):
1433
1651
  if field._value.is_integer():
1434
1652
  return self.represent_int(int(field._value))
1435
1653
  return self.represent_float(field._value)
1436
- if isinstance(field._value, bool):
1437
- return self.represent_bool(field._value)
1438
1654
  if field._value is _Unknown:
1439
- return self.represent_str('<<UNKNOWN>>')
1440
- return self.represent_str('<<UNEXPECTED>>')
1655
+ return self.represent_str("<<UNKNOWN>>")
1656
+ return self.represent_str("<<UNEXPECTED>>")
1441
1657
 
1442
- def represent_value(self, value):
1658
+ def represent_value(self, value: Value):
1443
1659
  match value._kind:
1444
- case 'struct_value' | 'Struct':
1445
- return self.represent_dict({k:v for k,v in value})
1446
- case 'list_value' | 'ListValue':
1660
+ case "struct_value" | "Struct":
1661
+ return self.represent_dict({k: v for k, v in value})
1662
+ case "list_value" | "ListValue":
1447
1663
  return self.represent_list([v for v in value])
1448
- case 'string_value':
1664
+ case "string_value":
1449
1665
  return self.represent_str(value._value.string_value)
1450
- case 'null_value':
1666
+ case "null_value":
1451
1667
  return self.represent_none(None)
1452
- case 'number_value':
1668
+ case "number_value":
1453
1669
  value = value._value.number_value
1454
1670
  if value.is_integer():
1455
1671
  return self.represent_int(int(value))
1456
1672
  return self.represent_float(value)
1457
- case 'bool_value':
1458
- return self.represent_bool(value._value.bool_value)
1459
- case 'Unknown':
1460
- return self.represent_str('<<UNKNOWN>>')
1673
+ case "bool_value":
1674
+ return self.represent_bool(bool(value._value.bool_value))
1675
+ case "Unknown":
1676
+ return self.represent_str("<<UNKNOWN>>")
1461
1677
  case _:
1462
- return self.represent_str('<<UNEXPECTED>>')
1678
+ return self.represent_str("<<UNEXPECTED>>")
1679
+
1463
1680
 
1464
1681
  _Dumper.add_representer(str, _Dumper.represent_str)
1465
1682
  _Dumper.add_representer(Message, _Dumper.represent_message_dict)