crossplane-function-pythonic 0.0.10__py3-none-any.whl → 0.1.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.
@@ -15,52 +15,50 @@
15
15
  #
16
16
  ##################################################################################
17
17
 
18
+ import base64
18
19
  import datetime
19
20
  import google.protobuf.struct_pb2
20
21
  import json
21
22
  import sys
22
23
  import yaml
23
24
 
25
+ _Unknown = object()
24
26
  append = sys.maxsize
25
27
 
26
28
 
27
29
  def Map(**kwargs):
28
- map = Values(None, None, None, Values.Type.MAP)
29
- for name, value in kwargs.items():
30
- map[name] = value
31
- return map
30
+ return Value(None, None, kwargs)
32
31
 
33
32
  def List(*args):
34
- list = Values(None, None, None, Values.Type.LIST)
35
- for ix, value in enumerate(args):
36
- list[ix] = value
37
- return list
33
+ return Value(None, None, args)
38
34
 
39
35
  def Unknown():
40
- return Values(None, None, None, Values.Type.UNKNOWN)
36
+ return Value(None, None)
41
37
 
42
38
  def Yaml(string, readOnly=None):
43
- return _Object(yaml.safe_load(string), readOnly)
39
+ if isinstance(string, (FieldMessage, Value)):
40
+ string = str(string)
41
+ return Value(None, None, yaml.safe_load(string), readOnly)
44
42
 
45
43
  def Json(string, readOnly=None):
46
- return _Object(json.loads(string), readOnly)
47
-
48
- def _Object(object, readOnly=None):
49
- if isinstance(object, dict):
50
- values = google.protobuf.struct_pb2.Struct()
51
- if len(object):
52
- values.update(object)
53
- return Values(None, None, values, Values.Type.MAP, readOnly)
54
- if isinstance(object, (list, tuple)):
55
- values = google.protobuf.struct_pb2.ListValue()
56
- if len(object):
57
- values.extend(object)
58
- return Values(None, None, values, Values.Type.LIST, readOnly)
59
- return object
44
+ if isinstance(string, (FieldMessage, Value)):
45
+ string = str(string)
46
+ return Value(None, None, json.loads(string), readOnly)
60
47
 
48
+ def B64Encode(string):
49
+ if isinstance(string, (FieldMessage, Value)):
50
+ string = str(string)
51
+ return base64.b64encode(string.encode('utf-8')).decode('utf-8')
52
+
53
+ def B64Decode(string):
54
+ if isinstance(string, (FieldMessage, Value)):
55
+ string = str(string)
56
+ return base64.b64decode(string.encode('utf-8')).decode('utf-8')
57
+
58
+ B64Decode = lambda s: base64.b64decode(s.encode('utf-8')).decode('utf-8')
61
59
 
62
60
  class Message:
63
- def __init__(self, parent, key, descriptor, message, readOnly=False):
61
+ def __init__(self, parent, key, descriptor, message=_Unknown, readOnly=False):
64
62
  self.__dict__['_parent'] = parent
65
63
  self.__dict__['_key'] = key
66
64
  self.__dict__['_descriptor'] = descriptor
@@ -77,29 +75,29 @@ class Message:
77
75
  field = self._descriptor.fields_by_name.get(key)
78
76
  if not field:
79
77
  raise AttributeError(obj=self, name=key)
80
- if self._message:
81
- value = getattr(self._message, key)
78
+ if self._message is _Unknown:
79
+ value = _Unknown
82
80
  else:
83
- value = None
84
- if value is None and field.has_default_value:
81
+ value = getattr(self._message, key)
82
+ if value is _Unknown and field.has_default_value:
85
83
  value = field.default_value
86
- if field.type == field.TYPE_MESSAGE:
87
- if field.message_type.name == 'Struct':
88
- value = Values(self, key, value, Values.Type.MAP, self._readOnly)
89
- elif field.message_type.name == 'ListValue':
90
- value = Values(self, key, value, Values.Type.LIST, self._readOnly)
91
- elif field.label == field.LABEL_REPEATED:
92
- if field.message_type.GetOptions().map_entry:
93
- value = MapMessage(self, key, field.message_type, value, self._readOnly)
94
- else:
95
- value = RepeatedMessage(self, key, field.message_type, value, self._readOnly)
84
+ if field.label == field.LABEL_REPEATED:
85
+ if field.type == field.TYPE_MESSAGE and field.message_type.GetOptions().map_entry:
86
+ value = MapMessage(self, key, field.message_type.fields_by_name['value'], value, self._readOnly)
87
+ else:
88
+ value = RepeatedMessage(self, key, field, value, self._readOnly)
89
+ elif field.type == field.TYPE_MESSAGE:
90
+ if field.message_type.name in ('Struct', 'ListValue'):
91
+ value = Value(self, key, value, self._readOnly)
96
92
  else:
97
93
  value = Message(self, key, field.message_type, value, self._readOnly)
94
+ else:
95
+ value = FieldMessage(self, key, field.type, value)
98
96
  self._cache[key] = value
99
97
  return value
100
98
 
101
99
  def __bool__(self):
102
- return self._message != None
100
+ return self._message is not _Unknown
103
101
 
104
102
  def __len__(self):
105
103
  return len(self._descriptor.fields)
@@ -112,7 +110,7 @@ class Message:
112
110
  yield key, self[key]
113
111
 
114
112
  def __hash__(self):
115
- if self._message:
113
+ if self._message is not _Unknown:
116
114
  return hash(tuple(hash(item) for item in sorted(iter(self), key=lambda item: item[0])))
117
115
  return 0
118
116
 
@@ -121,9 +119,9 @@ class Message:
121
119
  return False
122
120
  if self._descriptor.full_name != other._descriptor.full_name:
123
121
  return False
124
- if self._message is None:
125
- return other._message is None
126
- elif other._message is None:
122
+ if self._message is _Unknown:
123
+ return other._message is _Unknown
124
+ elif other._message is _Unknown:
127
125
  return False
128
126
  if len(self) != len(other):
129
127
  return False
@@ -147,26 +145,26 @@ class Message:
147
145
  else:
148
146
  name = str(self._key)
149
147
  if key is not None:
150
- if key.isidentifier():
151
- name += f".{key}"
148
+ if '.' in key:
149
+ name += f"[{key}]"
152
150
  else:
153
- name += f"['{key}']"
151
+ name += f".{key}"
154
152
  return name
155
153
  if key is not None:
156
154
  return str(key)
157
155
  return ''
158
156
 
159
- def _create_child(self, key, type=None):
157
+ def _create_child(self, key):
160
158
  if self._readOnly:
161
159
  raise ValueError(f"{self._readOnly} is read only")
162
- if self._message is None:
160
+ if self._message is _Unknown:
163
161
  self.__dict__['_message'] = self._parent._create_child(self._key)
164
162
  return getattr(self._message, key)
165
163
 
166
164
  def __call__(self, **kwargs):
167
165
  if self._readOnly:
168
166
  raise ValueError(f"{self._readOnly} is read only")
169
- if self._message is None:
167
+ if self._message is _Unknown:
170
168
  self.__dict__['_message'] = self._parent._create_child(self._key)
171
169
  self._message.Clear()
172
170
  self._cache.clear()
@@ -182,14 +180,19 @@ class Message:
182
180
  raise ValueError(f"{self._readOnly} is read only")
183
181
  if key not in self._descriptor.fields_by_name:
184
182
  raise AttributeError(obj=self, name=key)
185
- if self._message is None:
183
+ field = self._descriptor.fields_by_name[key]
184
+ if self._message is _Unknown:
186
185
  self.__dict__['_message'] = self._parent._create_child(self._key)
187
186
  if isinstance(value, Message):
188
187
  value = value._message
189
188
  elif isinstance(value, (MapMessage, RepeatedMessage)):
190
189
  value = value._messages
191
- elif isinstance(value, Values):
192
- value = value._values
190
+ elif isinstance(value, FieldMessage):
191
+ value = value._value
192
+ elif isinstance(value, Value):
193
+ value = value._raw
194
+ if field.type == field.TYPE_BYTES and isinstance(value, str):
195
+ value = value.encode('utf-8')
193
196
  setattr(self._message, key, value)
194
197
  self._cache.pop(key, None)
195
198
 
@@ -201,16 +204,16 @@ class Message:
201
204
  raise ValueError(f"{self._readOnly} is read only")
202
205
  if key not in self._descriptor.fields_by_name:
203
206
  raise AttributeError(obj=self, name=key)
204
- if self._message is not None:
205
- del self._message[key]
207
+ if self._message is not _Unknown:
208
+ self._message.ClearField(key)
206
209
  self._cache.pop(key, None)
207
210
 
208
211
 
209
212
  class MapMessage:
210
- def __init__(self, parent, key, descriptor, messages, readOnly=False):
213
+ def __init__(self, parent, key, field, messages=_Unknown, readOnly=False):
211
214
  self.__dict__['_parent'] = parent
212
215
  self.__dict__['_key'] = key
213
- self.__dict__['_field'] = descriptor.fields_by_name['value']
216
+ self.__dict__['_field'] = field
214
217
  self.__dict__['_messages'] = messages
215
218
  self.__dict__['_readOnly'] = readOnly
216
219
  self.__dict__['_cache'] = {}
@@ -221,40 +224,33 @@ class MapMessage:
221
224
  def __getitem__(self, key):
222
225
  if key in self._cache:
223
226
  return self._cache[key]
224
- if self._messages is None or key not in self._messages:
225
- value = None
227
+ if self._messages is _Unknown or key not in self._messages:
228
+ value = _Unknown
226
229
  else:
227
230
  value = self._messages[key]
228
231
  if value is None and self._field.has_default_value:
229
232
  value = self._field.default_value
230
233
  if self._field.type == self._field.TYPE_MESSAGE:
231
- if self._field.message_type.name == 'Struct':
232
- value = Values(self, key, value, Values.Type.MAP, self._readOnly)
233
- elif self._field.message_type.name == 'ListValue':
234
- value = Values(self, key, value, Values.Type.LIST, self._readOnly)
235
- elif self._field.label == self._field.LABEL_REPEATED:
236
- if self._field.message_type.GetOptions().map_entry:
237
- value = MapMessage(self, key, self._field.message_type, value, self._readOnly)
238
- else:
239
- value = RepeatedMessage(self, key, self._field.message_type, value, self._readOnly)
234
+ if self._field.message_type.name in ('Struct', 'ListValue'):
235
+ value = Value(self, key, value, self._readOnly)
240
236
  else:
241
237
  value = Message(self, key, self._field.message_type, value, self._readOnly)
242
- elif self._field.type == self._field.TYPE_BYTES and isinstance(value, bytes):
243
- value = value.decode('utf-8')
238
+ else:
239
+ value = FieldMessage(self, key, self._field.type, value)
244
240
  self._cache[key] = value
245
241
  return value
246
242
 
247
243
  def __bool__(self):
248
- return self._messages != None
244
+ return self._messages is not _Unknown
249
245
 
250
246
  def __len__(self):
251
- return 0 if self._messages is None else len(self._messages)
247
+ return 0 if self._messages is _Unknown else len(self._messages)
252
248
 
253
249
  def __contains__(self, key):
254
- return self._messages is not None and key in self._messages
250
+ return self._messages is not _Unknown and key in self._messages
255
251
 
256
252
  def __iter__(self):
257
- if self._messages is not None:
253
+ if self._messages is not _Unknown:
258
254
  for key in sorted(self._messages):
259
255
  yield key, self[key]
260
256
 
@@ -266,11 +262,14 @@ class MapMessage:
266
262
  def __eq__(self, other):
267
263
  if not isinstance(other, MapMessage):
268
264
  return False
269
- if self._descriptor.full_name != other._descriptor.full_name:
265
+ if self._field.type != other._field.type:
270
266
  return False
271
- if self._messages is None:
272
- return other._messages is None
273
- elif other._messages is None:
267
+ if self._field.type == self._field.TYPE_MESSAGE:
268
+ if self._field.message_type.full_name != other._field.message_type.full_name:
269
+ return False
270
+ if self._messages is _Unknown:
271
+ return other._messages is _Unknown
272
+ elif other._messages is _Unknown:
274
273
  return False
275
274
  if len(self) != len(other):
276
275
  return False
@@ -294,26 +293,26 @@ class MapMessage:
294
293
  else:
295
294
  name = str(self._key)
296
295
  if key is not None:
297
- if key.isidentifier():
298
- name += f".{key}"
296
+ if '.' in key:
297
+ name += f"[{key}]"
299
298
  else:
300
- name += f"['{key}']"
299
+ name += f".{key}"
301
300
  return name
302
301
  if key is not None:
303
302
  return str(key)
304
303
  return ''
305
304
 
306
- def _create_child(self, key, type=None):
305
+ def _create_child(self, key):
307
306
  if self._readOnly:
308
307
  raise ValueError(f"{self._readOnly} is read only")
309
- if self._messages is None:
308
+ if self._messages is _Unknown:
310
309
  self.__dict__['_messages'] = self._parent._create_child(self._key)
311
310
  return self._messages[key]
312
311
 
313
312
  def __call__(self, **kwargs):
314
313
  if self._readOnly:
315
314
  raise ValueError(f"{self._readOnly} is read only")
316
- if self._messages is None:
315
+ if self._messages is _Unknown:
317
316
  self.__dict__['_messages'] = self._parent._create_child(self._key)
318
317
  self._messages.clear()
319
318
  self._cache.clear()
@@ -327,10 +326,16 @@ class MapMessage:
327
326
  def __setitem__(self, key, message):
328
327
  if self._readOnly:
329
328
  raise ValueError(f"{self._readOnly} is read only")
330
- if self._messages is None:
329
+ if self._messages is _Unknown:
331
330
  self._messages = self._parent._create_child(self._key)
332
331
  if isinstance(message, Message):
333
332
  message = message._message
333
+ elif isinstance(message, (MapMessage, RepeatedMessage)):
334
+ message = message._messages
335
+ elif isinstance(message, FieldMessage):
336
+ message = message._value
337
+ elif isinstance(message, Value):
338
+ message = message._raw
334
339
  if self._field.type == self._field.TYPE_BYTES and isinstance(message, str):
335
340
  message = message.encode('utf-8')
336
341
  self._messages[key] = message
@@ -342,17 +347,17 @@ class MapMessage:
342
347
  def __delitem__(self, key):
343
348
  if self._readOnly:
344
349
  raise ValueError(f"{self._readOnly} is read only")
345
- if self._messages is not None:
350
+ if self._messages is not _Unknown:
346
351
  if key in self._messages:
347
352
  del self._messages[key]
348
353
  self._cache.pop(key, None)
349
354
 
350
355
 
351
356
  class RepeatedMessage:
352
- def __init__(self, parent, key, descriptor, messages, readOnly=False):
357
+ def __init__(self, parent, key, field, messages=_Unknown, readOnly=False):
353
358
  self._parent = parent
354
359
  self._key = key
355
- self._descriptor = descriptor
360
+ self._field = field
356
361
  self._messages = messages
357
362
  self._readOnly = readOnly
358
363
  self._cache = {}
@@ -360,45 +365,56 @@ class RepeatedMessage:
360
365
  def __getitem__(self, key):
361
366
  if key in self._cache:
362
367
  return self._cache[key]
363
- if self._messages is None or key >= len(self._messages):
364
- message = None
368
+ if self._messages is _Unknown or key >= len(self._messages):
369
+ value = _Unknown
365
370
  else:
366
- message = self._messages[key]
367
- value = Message(self, key, self._descriptor, message, self._readOnly)
371
+ value = self._messages[key]
372
+ if value is None and self._field.has_default_value:
373
+ value = self._field.default_value
374
+ if self._field.type == self._field.TYPE_MESSAGE:
375
+ if self._field.message_type.name in ('Struct', 'ListValue'):
376
+ value = Value(self, key, value, self._readOnly)
377
+ else:
378
+ value = Message(self, key, self._field.message_type, value, self._readOnly)
379
+ else:
380
+ value = FieldMessage(self, key, self._field.type, value)
368
381
  self._cache[key] = value
369
382
  return value
370
383
 
371
384
  def __bool__(self):
372
- return self._messages != None
385
+ return self._messages is not _Unknown
373
386
 
374
387
  def __len__(self):
375
- return 0 if self._messages is None else len(self._messages)
388
+ return 0 if self._messages is _Unknown else len(self._messages)
376
389
 
377
390
  def __contains__(self, value):
378
- if self._messages is not None:
391
+ if self._messages is not _Unknown:
379
392
  for message in self:
380
393
  if value == message:
381
394
  return True
382
395
  return False
383
396
 
384
397
  def __iter__(self):
385
- if self._messages is not None:
398
+ if self._messages is not _Unknown:
386
399
  for ix in range(len(self._messages)):
387
400
  yield self[ix]
388
401
 
389
402
  def __hash__(self):
390
- if self._messages is not None:
403
+ if self._messages is not _Unknown:
391
404
  return hash(tuple(hash(item) for item in self))
392
405
  return 0
393
406
 
394
407
  def __eq__(self, other):
395
408
  if not isinstance(other, RepeatedMessage):
396
409
  return False
397
- if self._descriptor.full_name != other._descriptor.full_name:
410
+ if self._field.type != other._field.type:
398
411
  return False
399
- if self._messages is None:
400
- return other._messages is None
401
- elif other._messages is None:
412
+ if self._field.type == self._field.TYPE_MESSAGE:
413
+ if self._field.message_type.full_name != other._field.message_type.full_name:
414
+ return False
415
+ if self._messages is _Unknown:
416
+ return other._messages is _Unknown
417
+ elif other._messages is _Unknown:
402
418
  return False
403
419
  if len(self) != len(other):
404
420
  return False
@@ -426,10 +442,10 @@ class RepeatedMessage:
426
442
  return str(key)
427
443
  return ''
428
444
 
429
- def _create_child(self, key, type=None):
445
+ def _create_child(self, key):
430
446
  if self._readOnly:
431
447
  raise ValueError(f"{self._readOnly} is read only")
432
- if self._messages is None:
448
+ if self._messages is _Unknown:
433
449
  self.__dict__['_messages'] = self._parent._create_child(self._key)
434
450
  while key >= len(self._messages):
435
451
  self._messages.add()
@@ -438,9 +454,9 @@ class RepeatedMessage:
438
454
  def __call__(self, *args):
439
455
  if self._readOnly:
440
456
  raise ValueError(f"{self._readOnly} is read only")
441
- if self._messages is None:
457
+ if self._messages is _Unknown:
442
458
  self.__dict__['_messages'] = self._parent._create_child(self._key)
443
- self._messages.Clear()
459
+ self._messages.clear()
444
460
  self._cache.clear()
445
461
  for arg in args:
446
462
  self.append(arg)
@@ -449,58 +465,135 @@ class RepeatedMessage:
449
465
  def __setitem__(self, key, message):
450
466
  if self._readOnly:
451
467
  raise ValueError(f"{self._readOnly} is read only")
452
- if self._messages is None:
468
+ if self._messages is _Unknown:
453
469
  self._messages = self._parent._create_child(self._key)
454
- if key == append:
455
- key = len(self._messages)
456
- elif key < 0:
470
+ if key < 0:
457
471
  key = len(self._messages) + key
458
- while key >= len(self._messages):
459
- self._messages.add()
460
472
  if isinstance(message, Message):
461
473
  message = message._message
462
- self._messages[key] = message
474
+ elif isinstance(message, (MapMessage, RepeatedMessage)):
475
+ message = message._messages
476
+ elif isinstance(message, FieldMessage):
477
+ message = message._value
478
+ elif isinstance(message, Value):
479
+ message = message._raw
480
+ if self._field.type == self._field.TYPE_BYTES and isinstance(message, str):
481
+ message = message.encode('utf-8')
482
+ if key >= len(self._messages):
483
+ self._messages.append(message)
484
+ else:
485
+ self._messages[key] = message
463
486
  self._cache.pop(key, None)
464
487
 
465
488
  def __delitem__(self, key):
466
489
  if self._readOnly:
467
490
  raise ValueError(f"{self._readOnly} is read only")
468
- if self._values is not None:
469
- del self._values[key]
491
+ if self._messages is not _Unknown:
492
+ del self._messages[key]
470
493
  self._cache.pop(key, None)
471
494
 
472
- def append(self, message=None):
495
+ def append(self, message=_Unknown):
473
496
  if self._readOnly:
474
497
  raise ValueError(f"{self._readOnly} is read only")
475
- if self._messages is None:
498
+ if self._messages is _Unknown:
476
499
  self._messages = self._parent._create_child(self._key)
477
- if message is None:
500
+ if message is _Unknown:
478
501
  message = self._messages.add()
479
502
  else:
480
503
  message = self._messages.append(message)
481
504
  return self[len(self._messages) - 1]
482
505
 
483
506
 
507
+ class FieldMessage:
508
+ def __init__(self, parent, key, kind, value):
509
+ self.__dict__['_parent'] = parent
510
+ self.__dict__['_key'] = key
511
+ self.__dict__['_kind'] = kind
512
+ self.__dict__['_value'] = value
513
+
514
+ def __bool__(self):
515
+ return bool(self._value)
516
+
517
+ def __len__(self):
518
+ return len(self._value)
519
+
520
+ def __contains__(self, key):
521
+ return key in self._value
522
+
523
+ def __hash__(self):
524
+ return hash(self._value)
525
+
526
+ def __eq__(self, other):
527
+ if isinstance(other, FieldMessage):
528
+ return self._value == other._value
529
+ return self._value == other
530
+
531
+ def __str__(self):
532
+ return str(self._value)
533
+
534
+ def __format__(self, spec=''):
535
+ return format(self._value, spec)
536
+
537
+ def __int__(self):
538
+ return int(self._value)
539
+
540
+ def __float__(self):
541
+ return float(self._value)
542
+
543
+ def _fullName(self, key=None):
544
+ if self._key is not None:
545
+ if self._parent is not None:
546
+ name = self._parent._fullName(self._key)
547
+ else:
548
+ name = str(self._key)
549
+ if key is not None:
550
+ if '.' in key:
551
+ name += f"[{key}]"
552
+ else:
553
+ name += f".{key}"
554
+ return name
555
+ if key is not None:
556
+ return str(key)
557
+ return ''
558
+
559
+
484
560
  class ProtobufValue:
485
561
  @property
486
562
  def _protobuf_value(self):
487
563
  return None
488
564
 
489
565
 
490
- class Values:
491
- class Type:
492
- UNKNOWN = 0
493
- MAP = 1
494
- LIST = 2
495
-
496
- def __init__(self, parent, key, values, type, readOnly=None):
566
+ class Value:
567
+ def __init__(self, parent, key, value=_Unknown, readOnly=None):
497
568
  self.__dict__['_parent'] = parent
498
569
  self.__dict__['_key'] = key
499
- self.__dict__['_values'] = values
500
- self.__dict__['_type'] = type
501
- self.__dict__['_readOnly'] = readOnly
570
+ self.__dict__['_dependencies'] = {}
502
571
  self.__dict__['_unknowns'] = {}
503
572
  self.__dict__['_cache'] = {}
573
+ self.__dict__['_readOnly'] = None
574
+ if isinstance(value, (google.protobuf.struct_pb2.Value, google.protobuf.struct_pb2.Struct, google.protobuf.struct_pb2.ListValue)) or value is _Unknown:
575
+ self.__dict__['_value'] = value
576
+ else:
577
+ self.__dict__['_value'] = google.protobuf.struct_pb2.Value()
578
+ if value is None:
579
+ self._value.null_value = 0
580
+ elif isinstance(value, dict):
581
+ self._value.struct_value.Clear()
582
+ for k, v in value.items():
583
+ self[k] = v
584
+ elif isinstance(value, (tuple, list)):
585
+ self._value.list_value.Clear()
586
+ for ix, v in enumerate(value):
587
+ self[ix] = v
588
+ elif isinstance(value, bool): # Must be before number check
589
+ self._value.bool_value = value
590
+ elif isinstance(value, (int, float)):
591
+ self._value.number_value = value
592
+ elif isinstance(value, str):
593
+ self._value.string_value = value
594
+ else:
595
+ raise ValueError(f"Unexpected Value type: {value.__class__}")
596
+ self.__dict__['_readOnly'] = readOnly
504
597
 
505
598
  def __getattr__(self, key):
506
599
  return self[key]
@@ -511,115 +604,201 @@ class Values:
511
604
  if key in self._unknowns:
512
605
  return self._unknowns[key]
513
606
  if isinstance(key, str):
514
- if not self._isMap:
515
- if not self._isUnknown:
516
- raise ValueError(f"Invalid key, must be a str for maps: {key}")
517
- self.__dict__['_type'] = self.Type.MAP
518
- if self._values is None or key not in self._values:
519
- struct_value = None
520
- else:
521
- struct_value = self._values.fields[key]
607
+ match self._kind:
608
+ case 'struct_value':
609
+ value = self._value.struct_value.fields.get(key, _Unknown)
610
+ case 'Struct':
611
+ value = self._value.fields.get(key, _Unknown)
612
+ case 'Unknown':
613
+ value = _Unknown
614
+ case _:
615
+ raise ValueError(f"Invalid key \"{key}\" for kind: {self._kind}")
522
616
  elif isinstance(key, int):
523
- if not self._isList:
524
- if not self._isUnknown:
525
- raise ValueError(f"Invalid key, must be an int for lists: {key}")
526
- self.__dict__['_type'] = self.Type.LIST
527
- if self._values is None or key >= len(self._values):
528
- struct_value = None
529
- else:
530
- struct_value = self._values.values[key]
531
- else:
532
- raise ValueError('Unexpected key type')
533
- if struct_value is None:
534
- value = Values(self, key, None, self.Type.UNKNOWN, self._readOnly)
617
+ match self._kind:
618
+ case 'list_value':
619
+ if key < len(self._value.list_value.values):
620
+ value = self._value.list_value.values[key]
621
+ else:
622
+ value = _Unknown
623
+ case 'ListValue':
624
+ if key < len(self._value.values):
625
+ value = self._value.values[key]
626
+ else:
627
+ value = _Unknown
628
+ case 'Unknown':
629
+ value = _Unknown
630
+ case _:
631
+ raise ValueError(f"Invalid key \"{key}\" for kind: {self._kind}")
535
632
  else:
536
- kind = struct_value.WhichOneof('kind')
537
- if kind is None:
538
- value = Values(self, key, None, self.Type.UNKNOWN, self._readOnly)
539
- elif kind == 'struct_value':
540
- value = Values(self, key, struct_value.struct_value, self.Type.MAP, self._readOnly)
541
- elif kind == 'list_value':
542
- value = Values(self, key, struct_value.list_value, self.Type.LIST, self._readOnly)
543
- elif kind == 'string_value':
544
- value = struct_value.string_value
545
- elif kind == 'number_value':
546
- value = struct_value.number_value
547
- if value.is_integer():
548
- value = int(value)
549
- elif kind == 'bool_value':
550
- value = struct_value.bool_value
551
- elif kind == 'null_value':
552
- value = None
553
- else:
554
- raise ValueError(f"Unexpected value kind: {kind}")
633
+ raise ValueError(f"Unexpected key type: {key.__class__}")
634
+ value = Value(self, key, value, self._readOnly)
555
635
  self._cache[key] = value
556
636
  return value
557
637
 
558
638
  def __bool__(self):
559
- return self._values != None
639
+ return not self._isUnknown
560
640
 
561
641
  def __len__(self):
562
- return 0 if self._values is None else len(self._values) + len(self._unknowns)
642
+ match self._kind:
643
+ case 'struct_value':
644
+ return len(self._value.struct_value.fields) + len(self._unknowns)
645
+ case 'Struct':
646
+ return len(self._value.fields) + len(self._unknowns)
647
+ case 'list_value':
648
+ return len(self._value.list_value.values) + len(self._unknowns)
649
+ case 'ListValue':
650
+ return len(self._value.values) + len(self._unknowns)
651
+ return 0
563
652
 
564
653
  def __contains__(self, item):
565
- if self._values is not None:
566
- if self._isMap:
567
- return item in self._values or item in self._unknowns
568
- if self._isList:
654
+ match self._kind:
655
+ case 'struct_value':
656
+ return item in self._value.struct_value.fields or item in self._unknowns
657
+ case 'Struct':
658
+ return item in self._value.fields or item in self._unknowns
659
+ case 'list_value' | 'ListValue':
569
660
  for value in self:
570
661
  if item == value:
571
662
  return True
572
663
  return False
573
664
 
574
665
  def __iter__(self):
575
- if self._values is not None:
576
- if self._isMap:
577
- for key in sorted(set(self._values) | set(self._unknowns.keys())):
666
+ match self._kind:
667
+ case 'struct_value':
668
+ for key in sorted(set(self._value.struct_value.fields) | set(self._unknowns.keys())):
578
669
  yield key, self[key]
579
- elif self._isList:
580
- for ix in range(len(self._values)):
670
+ case 'Struct':
671
+ for key in sorted(set(self._value.fields) | set(self._unknowns.keys())):
672
+ yield key, self[key]
673
+ case 'list_value':
674
+ for ix in range(len(self._value.list_value.values)):
581
675
  yield self[ix]
582
676
  for ix in sorted(self._unknowns.keys()):
583
- if ix >= len(self._values):
677
+ if ix >= len(self._value.list_value.values):
678
+ yield self[ix]
679
+ case 'ListValue':
680
+ for ix in range(len(self._value.values)):
681
+ yield self[ix]
682
+ for ix in sorted(self._unknowns.keys()):
683
+ if ix >= len(self._value.values):
584
684
  yield self[ix]
585
685
 
586
686
  def __hash__(self):
587
- if self._values is not None:
588
- if self._isMap:
687
+ match self._kind:
688
+ case 'struct_value' | 'Struct':
589
689
  return hash(tuple(hash(item) for item in sorted(iter(self), key=lambda item: item[0])))
590
- if self._isList:
690
+ case 'list_value' | 'ListValue':
591
691
  return hash(tuple(hash(item) for item in self))
592
- return self._type
692
+ case 'string_value':
693
+ return hash(self._value.string_value)
694
+ case 'null_value':
695
+ return hash(None)
696
+ case 'number_value':
697
+ return hash(self._value.number_value)
698
+ case 'bool_value':
699
+ return hash(self._value.bool_value)
700
+ return 0
593
701
 
594
702
  def __eq__(self, other):
595
- if not isinstance(other, Values):
596
- return False
597
- if self._type != other._type:
703
+ kind = self._kind
704
+ if isinstance(other, Value) and other._kind != kind:
598
705
  return False
599
- if self._values is None:
600
- return other._values is None
601
- elif other._values is None:
602
- return False
603
- if len(self) != len(other):
604
- return False
605
- if self._isMap:
606
- for key, value in self:
607
- if key not in other:
706
+ match kind:
707
+ case 'struct_value' | 'Struct':
708
+ if not isinstance(other, (Value, dict)):
608
709
  return False
609
- if value != other[key]:
710
+ if len(self) != len(other):
610
711
  return False
611
- if self._isList:
612
- for ix, value in enumerate(self):
613
- if value != other[ix]:
712
+ for key, value in self:
713
+ if key not in other:
714
+ return False
715
+ if value != other[key]:
716
+ return False
717
+ return True
718
+ case 'list_value' | 'ListValue':
719
+ if not isinstance(other, (Value, tuple, list)):
614
720
  return False
615
- return True
721
+ if len(self) != len(other):
722
+ return False
723
+ for ix, value in enumerate(self):
724
+ if value != other[ix]:
725
+ return False
726
+ return True
727
+ case 'Unknown':
728
+ if isinstance(other, Value):
729
+ return other._isUnknown
730
+ return False
731
+ case 'string_value':
732
+ if isinstance(other, Value):
733
+ return self._value.string_value == other._value.string_value
734
+ if isinstance(other, str):
735
+ return self._value.string_value == other
736
+ return False
737
+ case 'null_value':
738
+ if isinstance(other, Value):
739
+ return True
740
+ return other is None
741
+ case 'number_value':
742
+ if isinstance(other, Value):
743
+ return self._value.number_value == other._value.number_value
744
+ if isinstance(other, (int, float)):
745
+ return self._value.number_value == other
746
+ return False
747
+ case 'bool_value':
748
+ if isinstance(other, Value):
749
+ return self._value.bool_value == other._value.bool_value
750
+ if isinstance(other, bool):
751
+ return self._value.bool_value == other
752
+ return False
753
+ return False
616
754
 
617
755
  def __str__(self):
618
- return format(self)
756
+ return format(self, '')
619
757
 
620
758
  def __format__(self, spec='yaml'):
759
+ if not spec:
760
+ match self._kind:
761
+ case 'Unknown':
762
+ return '<<UNKNOWN>>'
763
+ case 'string_value':
764
+ return self._value.string_value
765
+ case 'null_value':
766
+ return 'null'
767
+ case 'number_value':
768
+ value = self._value.number_value
769
+ if value.is_integer():
770
+ value = int(value)
771
+ return str(value)
772
+ case 'bool_value':
773
+ return 'true' if self._value.bool_value else 'false'
621
774
  return _formatObject(self, spec)
622
775
 
776
+ def __int__(self):
777
+ kind = self._kind
778
+ match kind:
779
+ case 'string_value':
780
+ return int(self._value.string_value)
781
+ case 'number_value':
782
+ return int(self._value.number_value)
783
+ case 'bool_value':
784
+ return int(self._value.bool_value)
785
+ case 'Unknown':
786
+ return 0
787
+ raise TypeError(f"Cannot convert kind to integer: {kind}")
788
+
789
+ def __float__(self):
790
+ kind = self._kind
791
+ match kind:
792
+ case 'string_value':
793
+ return float(self._value.string_value)
794
+ case 'number_value':
795
+ return float(self._value.number_value)
796
+ case 'bool_value':
797
+ return float(self._value.bool_value)
798
+ case 'Unknown':
799
+ return 0.0
800
+ raise TypeError(f"Cannot convert kind to float: {kind}")
801
+
623
802
  def _fullName(self, key=None):
624
803
  if self._key is not None:
625
804
  if self._parent is not None:
@@ -638,60 +817,21 @@ class Values:
638
817
  if isinstance(key, int):
639
818
  name += f"[{key}]"
640
819
  else:
641
- if key.isidentifier():
642
- name += f".{key}"
820
+ if '.' in key:
821
+ name += f"[{key}]"
643
822
  else:
644
- name += f"['{key}']"
823
+ name += f".{key}"
645
824
  return name
646
825
  if key is not None:
647
826
  return str(key)
648
827
  return ''
649
828
 
650
- def _create_child(self, key, type):
651
- if self._readOnly:
652
- raise ValueError(f"{self._readOnly} is read only")
653
- if isinstance(key, str):
654
- if not self._isMap:
655
- if not self._isUnknown:
656
- raise ValueError('Invalid key, must be a str for maps')
657
- self.__dict__['_type'] = self.Type.MAP
658
- if self._values is None:
659
- if self._parent is None:
660
- self.__dict__['_values'] = google.protobuf.struct_pb2.Struct()
661
- else:
662
- self.__dict__['_values'] = self._parent._create_child(self._key, self._type)
663
- struct_value = self._values.fields[key]
664
- elif isinstance(key, int):
665
- if not self._isList:
666
- if not self._isUnknown:
667
- raise ValueError('Invalid key, must be an int for lists')
668
- self.__dict__['_type'] = self.Type.LIST
669
- if self._values is None:
670
- if self._parent is None:
671
- self.__dict__['_values'] = google.protobuf.struct_pb2.ListValue()
672
- else:
673
- self.__dict__['_values'] = self._parent._create_child(self._key, self._type)
674
- while key >= len(self._values.values):
675
- self._values.values.add()
676
- struct_value = self._values.values[key]
677
- else:
678
- raise ValueError('Unexpected key type')
679
- if type == self.Type.MAP:
680
- if not struct_value.HasField('struct_value'):
681
- struct_value.struct_value.Clear()
682
- return struct_value.struct_value
683
- if type == self.Type.LIST:
684
- if not struct_value.HasField('list_value'):
685
- struct_value.list_value.Clear()
686
- return struct_value.list_value
687
- raise ValueError(f"Unexpected type: {type}")
688
-
689
829
  def __call__(self, *args, **kwargs):
690
830
  if self._readOnly:
691
831
  raise ValueError(f"{self._readOnly} is read only")
692
- self.__dict__['_values'] = None
693
- self.__dict__['_type'] = self.Type.UNKNOWN
832
+ self.__dict__['_value'] = google.protobuf.struct_pb2.Value()
694
833
  self._cache.clear()
834
+ self._dependencies.clear()
695
835
  self._unknowns.clear()
696
836
  if len(kwargs):
697
837
  if len(args):
@@ -710,27 +850,15 @@ class Values:
710
850
  if self._readOnly:
711
851
  raise ValueError(f"{self._readOnly} is read only")
712
852
  if isinstance(key, str):
713
- if not self._isMap:
714
- if not self._isUnknown:
715
- raise ValueError('Invalid key, must be a str for maps')
716
- self.__dict__['_type'] = self.Type.MAP
717
- if self._values is None:
718
- if self._parent is None:
719
- self.__dict__['_values'] = google.protobuf.struct_pb2.Struct()
720
- else:
721
- self.__dict__['_values'] = self._parent._create_child(self._key, self._type)
722
- values = self._values.fields
853
+ if self._ensure_map() == 'struct_value':
854
+ values = self._value.struct_value.fields
855
+ else:
856
+ values = self._value.fields
723
857
  elif isinstance(key, int):
724
- if not self._isList:
725
- if not self._isUnknown:
726
- raise ValueError('Invalid key, must be an int for lists')
727
- self.__dict__['_type'] = self.Type.LIST
728
- if self._values is None:
729
- if self._parent is None:
730
- self.__dict__['_values'] = google.protobuf.struct_pb2.ListValue()
731
- else:
732
- self.__dict__['_values'] = self._parent._create_child(self._key, self._type)
733
- values = self._values.values
858
+ if self._ensure_list() == 'list_value':
859
+ values = self._value.list_value.values
860
+ else:
861
+ values = self._value.values
734
862
  if key == append:
735
863
  key = len(values)
736
864
  elif key < 0:
@@ -740,6 +868,7 @@ class Values:
740
868
  else:
741
869
  raise ValueError('Unexpected key type')
742
870
  self._cache.pop(key, None)
871
+ self._dependencies.pop(key, None)
743
872
  self._unknowns.pop(key, None)
744
873
  if isinstance(value, ProtobufValue):
745
874
  value = value._protobuf_value
@@ -759,79 +888,217 @@ class Values:
759
888
  values[key].list_value.Clear()
760
889
  for ix, v in enumerate(value):
761
890
  self[key][ix] = v
762
- elif isinstance(value, Values):
763
- if value._isMap:
764
- values[key].struct_value.Clear()
765
- for k, v in value:
766
- self[key][k] = v
767
- elif value._isList:
768
- values[key].list_value.Clear()
769
- for ix, v in enumerate(value):
770
- self[key][ix] = v
891
+ elif isinstance(value, FieldMessage):
892
+ self._dependencies[key] = value
893
+ if isinstance(value._value, str):
894
+ values[key].string_value = value._value
895
+ elif isinstance(value._value, bytes):
896
+ values[key].string_value = value._value.decode('utf-8')
897
+ elif value._value is None:
898
+ values[key].null_value = value._value.null_value
899
+ elif isinstance(value._value, (int, float)):
900
+ values[key].number_value = value._value
901
+ elif isinstance(value._value, bool):
902
+ values[key].bool_value = value._value
903
+ elif value._value is _Unknown:
904
+ self._setUnknown(key, value)
771
905
  else:
772
- self._unknowns[key] = value
773
- if self._isMap:
774
- if key in values:
775
- del values[key]
776
- elif self._isList:
777
- if key < len(values):
778
- values[key].Clear()
779
- for ix in reversed(range(len(values))):
780
- if ix not in self._unknowns:
781
- break
782
- del values[ix]
906
+ raise ValueError(f"Unexpected field type: {value._value.__class__}")
907
+ elif isinstance(value, Value):
908
+ self._dependencies[key] = value
909
+ match value._kind:
910
+ case 'struct_value' | 'Struct':
911
+ values[key].struct_value.Clear()
912
+ for k, v in value:
913
+ self[key][k] = v
914
+ case 'list_value' | 'ListValue':
915
+ values[key].list_value.Clear()
916
+ for ix, v in enumerate(value):
917
+ self[key][ix] = v
918
+ case 'string_value':
919
+ values[key].string_value = value._value.string_value
920
+ case 'null_value':
921
+ values[key].null_value = value._value.null_value
922
+ case 'number_value':
923
+ values[key].number_value = value._value.number_value
924
+ case 'bool_value':
925
+ values[key].bool_value = value._value.bool_value
926
+ case 'Unknown':
927
+ self._setUnknown(key, value)
928
+ case _:
929
+ raise ValueError(f"Unexpected value kind: {value._kind}")
783
930
  else:
784
931
  raise ValueError(f"Unexpected type: {value.__class__}")
785
932
 
933
+ @property
934
+ def _raw(self):
935
+ match self._kind:
936
+ case 'struct_value':
937
+ return self._value.struct_value
938
+ case 'list_value':
939
+ return self._value.list_value
940
+ case 'string_value':
941
+ return self._value.string_value
942
+ case 'null_value':
943
+ return self._value.null_value
944
+ case 'number_value':
945
+ return self._value.number_value
946
+ case 'bool_value':
947
+ return self._value.bool_value
948
+ case 'Struct' | 'ListValue':
949
+ return self._value
950
+ case 'Unknown':
951
+ return _Unknown
952
+
953
+ def _setUnknown(self, key, value):
954
+ self._dependencies.pop(key, None)
955
+ self._unknowns[key] = value
956
+ match self._kind:
957
+ case 'struct_value':
958
+ if key in self._value.struct_value.fields:
959
+ del self._value.struct_value[key]
960
+ case 'Struct':
961
+ if key in self._value.fields:
962
+ del self._value[key]
963
+ case 'list_value':
964
+ if key < len(self._value.list_value.values):
965
+ self._value.list_value.values[key].Clear()
966
+ for ix in reversed(range(len(self._value.list_value.values))):
967
+ if ix not in self._unknowns:
968
+ break
969
+ del self._value.list_value[ix]
970
+ case 'ListValue':
971
+ if key < len(self._value.values):
972
+ self._value.values[key].Clear()
973
+ for ix in reversed(range(len(self._value.values))):
974
+ if ix not in self._unknowns:
975
+ break
976
+ del self._value[ix]
977
+
786
978
  def __delattr__(self, key):
787
979
  del self[key]
788
980
 
789
981
  def __delitem__(self, key):
790
982
  if self._readOnly:
791
983
  raise ValueError(f"{self._readOnly} is read only")
984
+ kind = self._kind
985
+ if kind == 'Unknown':
986
+ return
792
987
  if isinstance(key, str):
793
- if not self._isMap:
794
- if not self._isUnknown:
795
- raise ValueError('Invalid key, must be a str for maps')
796
- self.__dict__['_type'] = self.Type.MAP
797
- if self._values is not None:
798
- if key in self._values:
799
- del self._values[key]
800
- self._cache.pop(key, None)
801
- self._unknowns.pop(key, None)
988
+ match kind:
989
+ case 'struct_value':
990
+ if key in self._value.struct_value.fields:
991
+ del self._value.struct_value[key]
992
+ case 'Struct':
993
+ if key in self._value.fields:
994
+ del self._value[key]
995
+ case _:
996
+ raise ValueError(f"Invalid key \"{key}\" for kind: {self._kind}")
997
+ self._cache.pop(key, None)
998
+ self._dependencies.pop(key, None)
999
+ self._unknowns.pop(key, None)
802
1000
  elif isinstance(key, int):
803
- if not self._isList:
804
- if not self._isUnknown:
805
- raise ValueError('Invalid key, must be an int for lists')
806
- self.__dict__['_type'] = self.Type.LIST
807
- if self._values is not None:
808
- if key < len(self._values):
809
- del self._values[key]
810
- self._cache.pop(key, None)
811
- self._unknowns.pop(key, None)
812
- for ix in sorted(self._unknowns.keys()):
813
- if ix > key:
814
- self._cache.pop(ix, None)
815
- self._unknowns[ix - 1] = self._unknowns[ix]
816
- del self._unknowns[ix]
817
- for ix in reversed(range(len(self._values))):
818
- if ix not in self._unknowns:
819
- break
820
- del self._values[ix]
1001
+ match kind:
1002
+ case 'list_value':
1003
+ values = self._value.list_value
1004
+ case 'ListValue':
1005
+ values = self._value
1006
+ case _:
1007
+ raise ValueError(f"Invalid key \"{key}\" for kind: {self._kind}")
1008
+ if key < len(values.values):
1009
+ del values[key]
1010
+ self._cache.pop(key, None)
1011
+ self._dependencies.pop(key, None)
1012
+ self._unknowns.pop(key, None)
1013
+ for ix in sorted(self._dependencies.keys()):
1014
+ if ix > key:
1015
+ self._cache.pop(ix, None)
1016
+ self._dependencies[ix - 1] = self._dependences[ix]
1017
+ del self._dependencies[ix]
1018
+ for ix in sorted(self._unknowns.keys()):
1019
+ if ix > key:
1020
+ self._cache.pop(ix, None)
1021
+ self._unknowns[ix - 1] = self._unknowns[ix]
1022
+ del self._unknowns[ix]
1023
+ for ix in reversed(range(len(values.values))):
1024
+ if ix not in self._unknowns:
1025
+ break
1026
+ del values[ix]
821
1027
  else:
822
1028
  raise ValueError('Unexpected key type')
823
1029
 
1030
+ def _create_child(self, key):
1031
+ if self._readOnly:
1032
+ raise ValueError(f"{self._readOnly} is read only")
1033
+ if isinstance(key, str):
1034
+ if self._ensure_map() == 'struct_value':
1035
+ fields = self._value.struct_value.fields
1036
+ else:
1037
+ fields = self._value.fields
1038
+ fields[key].Clear()
1039
+ return fields[key]
1040
+ if isinstance(key, int):
1041
+ if self._ensure_list() == 'list_value':
1042
+ values = self._value.list_value.values
1043
+ else:
1044
+ values = self._value.values
1045
+ while key >= len(values):
1046
+ values.add()
1047
+ values[key].Clear()
1048
+ return values[key]
1049
+ raise ValueError('Unexpected key type')
1050
+
1051
+ def _ensure_map(self):
1052
+ kind = self._kind
1053
+ if kind == 'Unknown':
1054
+ if self._parent is None:
1055
+ self.__dict__['_value'] = google.protobuf.struct_pb2.Value()
1056
+ else:
1057
+ self.__dict__['_value'] = self._parent._create_child(self._key)
1058
+ if isinstance(self._value, google.protobuf.struct_pb2.Value) and self._value.WhichOneof('kind') is None:
1059
+ self._value.struct_value.Clear()
1060
+ kind = self._kind
1061
+ if kind not in ('struct_value', 'Struct'):
1062
+ raise ValueError(f"Invalid map kind: {kind}")
1063
+ return kind
1064
+
1065
+ def _ensure_list(self):
1066
+ kind = self._kind
1067
+ if kind == 'Unknown':
1068
+ if self._parent is None:
1069
+ self.__dict__['_value'] = google.protobuf.struct_pb2.Value()
1070
+ else:
1071
+ self.__dict__['_value'] = self._parent._create_child(self._key)
1072
+ if isinstance(self._value, google.protobuf.struct_pb2.Value) and self._value.WhichOneof('kind') is None:
1073
+ self._value.list_value.Clear()
1074
+ kind = self._kind
1075
+ if kind not in ('list_value', 'ListValue'):
1076
+ raise ValueError(f"Invalid list kind: {kind}")
1077
+ return kind
1078
+
1079
+ @property
1080
+ def _kind(self):
1081
+ if isinstance(self._value, google.protobuf.struct_pb2.Value):
1082
+ return self._value.WhichOneof('kind') or 'Unknown'
1083
+ if isinstance(self._value, google.protobuf.struct_pb2.Struct):
1084
+ return 'Struct'
1085
+ if isinstance(self._value, google.protobuf.struct_pb2.ListValue):
1086
+ return 'ListValue'
1087
+ if self._value is _Unknown:
1088
+ return 'Unknown'
1089
+ raise ValueError(f"Unexpected value type: {self._value.__class__}")
1090
+
824
1091
  @property
825
1092
  def _isUnknown(self):
826
- return self._type == self.Type.UNKNOWN
1093
+ return self._kind == 'Unknown'
827
1094
 
828
1095
  @property
829
1096
  def _isMap(self):
830
- return self._type == self.Type.MAP
1097
+ return self._kind in ('struct_value', 'Struct')
831
1098
 
832
1099
  @property
833
1100
  def _isList(self):
834
- return self._type == self.Type.LIST
1101
+ return self._kind in ('list_value', 'ListValue')
835
1102
 
836
1103
  @property
837
1104
  def _getUnknowns(self):
@@ -840,45 +1107,77 @@ class Values:
840
1107
  unknowns[self._fullName(key)] = unknown._fullName()
841
1108
  if self._isMap:
842
1109
  for key, value in self:
843
- if isinstance(value, Values):
1110
+ if isinstance(value, Value):
844
1111
  unknowns.update(value._getUnknowns)
845
1112
  elif self._isList:
846
1113
  for value in self:
847
- if isinstance(value, Values):
1114
+ if isinstance(value, Value):
848
1115
  unknowns.update(value._getUnknowns)
849
1116
  return unknowns
850
1117
 
1118
+ @property
1119
+ def _getDependencies(self):
1120
+ dependencies = {}
1121
+ for key, dependency in self._dependencies.items():
1122
+ dependencies[self._fullName(key)] = dependency._fullName()
1123
+ for key, unknown in self._unknowns.items():
1124
+ dependencies[self._fullName(key)] = unknown._fullName()
1125
+ if self._isMap:
1126
+ for key, value in self:
1127
+ if isinstance(value, Value):
1128
+ dependencies.update(value._getDependencies)
1129
+ elif self._isList:
1130
+ for value in self:
1131
+ if isinstance(value, Value):
1132
+ dependencies.update(value._getDependencies)
1133
+ return dependencies
1134
+
851
1135
  def _patchUnknowns(self, patches):
852
- for key in [key for key in self._unknowns.keys()]:
1136
+ for key in list(self._unknowns.keys()):
853
1137
  self[key] = patches[key]
854
1138
  if self._isMap:
855
1139
  for key, value in self:
856
- if isinstance(value, Values) and len(value):
1140
+ if isinstance(value, Value) and len(value):
857
1141
  patch = patches[key]
858
- if isinstance(patch, Values) and patch._type == value._type and len(patch):
1142
+ if isinstance(patch, Value) and patch._type == value._type and len(patch):
859
1143
  value._patchUnknowns(patch)
860
1144
  elif self._isList:
861
1145
  for ix, value in enumerate(self):
862
- if isinstance(value, Values) and len(value):
1146
+ if isinstance(value, Value) and len(value):
863
1147
  patch = patches[ix]
864
- if isinstance(patch, Values) and patch._type == value._type and len(patch):
1148
+ if isinstance(patch, Value) and patch._type == value._type and len(patch):
865
1149
  value._patchUnknowns(patch)
866
1150
 
867
-
868
- def _formatObject(object, spec):
869
- if spec == 'json':
870
- return json.dumps(object, indent=2, cls=_JSONEncoder)
871
- if spec == 'jsonc':
872
- return json.dumps(object, separators=(',', ':'), cls=_JSONEncoder)
873
- if spec == 'protobuf':
874
- if isinstance(object, Message):
875
- return str(object._message)
876
- if isinstance(object, (MapMessage, RepeatedMessage)):
877
- return str(object._messages)
878
- if isinstance(object, Values):
879
- return str(object._values)
880
- return format(object)
881
- return yaml.dump(object, Dumper=_Dumper)
1151
+ def _renderUnknowns(self, trimFullName):
1152
+ for key, unknown in list(self._unknowns.items()):
1153
+ self[key] = f"UNKNOWN:{trimFullName(unknown._fullName())}"
1154
+ self._dependencies[key] = unknown
1155
+ if self._isMap:
1156
+ for key, value in self:
1157
+ if isinstance(value, Value) and len(value):
1158
+ value._renderUnknowns(trimFullName)
1159
+ elif self._isList:
1160
+ for ix, value in enumerate(self):
1161
+ if isinstance(value, Value) and len(value):
1162
+ value._renderUnknowns(trimFullName)
1163
+
1164
+
1165
+ def _formatObject(object, spec='yaml'):
1166
+ match spec:
1167
+ case 'json':
1168
+ return json.dumps(object, indent=2, cls=_JSONEncoder)
1169
+ case 'jsonc':
1170
+ return json.dumps(object, separators=(',', ':'), cls=_JSONEncoder)
1171
+ case 'protobuf':
1172
+ if isinstance(object, Message):
1173
+ return str(object._message)
1174
+ if isinstance(object, (MapMessage, RepeatedMessage)):
1175
+ return str(object._messages)
1176
+ if isinstance(object, Value):
1177
+ return str(object._value)
1178
+ return format(object)
1179
+ case _:
1180
+ return yaml.dump(object, Dumper=_Dumper)
882
1181
 
883
1182
 
884
1183
  class _JSONEncoder(json.JSONEncoder):
@@ -891,17 +1190,32 @@ class _JSONEncoder(json.JSONEncoder):
891
1190
  if object:
892
1191
  return [value for value in object]
893
1192
  return None
894
- if isinstance(object, Values):
895
- if object._isMap:
896
- return {key: value for key, value in object}
897
- if object._isList:
898
- return [value for value in object]
899
- if object._isUnknown:
900
- return '<<UNKNOWN>>'
901
- return '<<UNEXPECTED>>'
1193
+ if isinstance(object, FieldMessage):
1194
+ return object._value
1195
+ if isinstance(object, Value):
1196
+ match object._kind:
1197
+ case 'struct_value' | 'Struc':
1198
+ return {key: value for key, value in object}
1199
+ case 'list_value' | 'ListValue':
1200
+ return [value for value in object]
1201
+ case 'string_value':
1202
+ return object._value.string_value
1203
+ case 'null_value':
1204
+ return None
1205
+ case 'number_value':
1206
+ value = object._value.number_value
1207
+ if value.is_integer():
1208
+ value = int(value)
1209
+ return value
1210
+ case 'bool_value':
1211
+ return object._value.bool_value
1212
+ case 'Unknown':
1213
+ return '<<UNKNOWN>>'
1214
+ case _:
1215
+ return '<<UNEXPECTED>>'
902
1216
  if isinstance(object, datetime.datetime):
903
1217
  return object.isoformat()
904
- return super(JSONEncoder, self).default(object)
1218
+ return super(_JSONEncoder, self).default(object)
905
1219
 
906
1220
 
907
1221
  class _Dumper(yaml.SafeDumper):
@@ -915,17 +1229,50 @@ class _Dumper(yaml.SafeDumper):
915
1229
  def represent_message_list(self, messages):
916
1230
  return self.represent_list([value for value in messages])
917
1231
 
918
- def represent_values(self, values):
919
- if values._isMap:
920
- return self.represent_dict({key: value for key, value in values})
921
- if values._isList:
922
- return self.represent_list([value for value in values])
923
- if values._isUnknown:
924
- return self.represent_scalar('tag:yaml.org,2002:str', '<<UNKNOWN>>')
925
- return self.represent_scalar('tag:yaml.org,2002:str', '<<UNEXPECTED>>')
1232
+ def represent_message_field(self, field):
1233
+ if isinstance(field._value, str):
1234
+ return self.represent_str(field._value)
1235
+ if isinstance(field._value, bytes):
1236
+ return self.represent_binary(field._value)
1237
+ if field._value is None:
1238
+ return self.represent_none()
1239
+ if isinstance(field._value, int):
1240
+ return self.represent_int(field._value)
1241
+ if isinstance(field._value, float):
1242
+ if field._value.is_integer():
1243
+ return self.represent_int(int(field._value))
1244
+ return self.represent_float(field._value)
1245
+ if isinstance(field._value, bool):
1246
+ return self.represent_bool(field._value)
1247
+ if field._value is _Unknown:
1248
+ return self.represent_str('<<UNKNOWN>>')
1249
+ return self.represent_str('<<UNEXPECTED>>')
1250
+
1251
+ def represent_value(self, value):
1252
+ match value._kind:
1253
+ case 'struct_value' | 'Struct':
1254
+ return self.represent_dict({k:v for k,v in value})
1255
+ case 'list_value' | 'ListValue':
1256
+ return self.represent_list([v for v in value])
1257
+ case 'string_value':
1258
+ return self.represent_str(value._value.string_value)
1259
+ case 'null_value':
1260
+ return self.represent_none(None)
1261
+ case 'number_value':
1262
+ value = value._value.number_value
1263
+ if value.is_integer():
1264
+ return self.represent_int(int(value))
1265
+ return self.represent_float(value)
1266
+ case 'bool_value':
1267
+ return self.represent_bool(value._value.bool_value)
1268
+ case 'Unknown':
1269
+ return self.represent_str('<<UNKNOWN>>')
1270
+ case _:
1271
+ return self.represent_str('<<UNEXPECTED>>')
926
1272
 
927
1273
  _Dumper.add_representer(str, _Dumper.represent_str)
928
1274
  _Dumper.add_representer(Message, _Dumper.represent_message_dict)
929
1275
  _Dumper.add_representer(MapMessage, _Dumper.represent_message_dict)
930
1276
  _Dumper.add_representer(RepeatedMessage, _Dumper.represent_message_list)
931
- _Dumper.add_representer(Values, _Dumper.represent_values)
1277
+ _Dumper.add_representer(FieldMessage, _Dumper.represent_message_field)
1278
+ _Dumper.add_representer(Value, _Dumper.represent_value)