Skip to content

Commit 023a98c

Browse files
authored
[lldb] Add Pythonic API to SBStructuredData extension (#155061)
* Adds `dynamic` property to automatically convert `SBStructuredData` instances to the associated Python type (`str`, `int`, `float`, `bool`, `NoneType`, etc) * Implements `__getitem__` for Pythonic array and dictionary subscripting * Subscripting return the result of the `dynamic` property * Updates `__iter__` to support dictionary instances (supporting `for` loops) * Adds conversion to `str`, `int`, and `float` * Adds Pythonic `bool` conversion With these changes, these two expressions are equal: ```py data["name"] == data.GetValueForKey("name").GetStringValue(1024) ``` Additionally did some cleanup in TestStructuredDataAPI.py.
1 parent cc9acb9 commit 023a98c

File tree

2 files changed

+224
-30
lines changed

2 files changed

+224
-30
lines changed

lldb/bindings/interface/SBStructuredDataExtensions.i

Lines changed: 121 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -3,16 +3,133 @@ STRING_EXTENSION_OUTSIDE(SBStructuredData)
33
%extend lldb::SBStructuredData {
44
#ifdef SWIGPYTHON
55
%pythoncode%{
6-
def __int__(self):
7-
return self.GetSignedInteger()
8-
96
def __len__(self):
107
'''Return the number of element in a lldb.SBStructuredData object.'''
118
return self.GetSize()
129

1310
def __iter__(self):
1411
'''Iterate over all the elements in a lldb.SBStructuredData object.'''
15-
return lldb_iter(self, 'GetSize', 'GetItemAtIndex')
12+
data_type = self.GetType()
13+
if data_type == eStructuredDataTypeArray:
14+
for i in range(self.GetSize()):
15+
yield self.GetItemAtIndex(i).dynamic
16+
return
17+
elif data_type == eStructuredDataTypeDictionary:
18+
keys = SBStringList()
19+
self.GetKeys(keys)
20+
return iter(keys)
21+
else:
22+
raise TypeError(f"cannot iterate {self.type_name(data_type)} type")
23+
24+
def __getitem__(self, key):
25+
data_type = self.GetType()
26+
if data_type == eStructuredDataTypeArray:
27+
if not isinstance(key, int):
28+
raise TypeError("subscript index must be an integer")
29+
count = len(self)
30+
if -count <= key < count:
31+
key %= count
32+
return self.GetItemAtIndex(key).dynamic
33+
raise IndexError("index out of range")
34+
elif data_type == eStructuredDataTypeDictionary:
35+
if not isinstance(key, str):
36+
raise TypeError("subscript key must be a string")
37+
return self.GetValueForKey(key).dynamic
38+
else:
39+
raise TypeError(f"cannot subscript {self.type_name(data_type)} type")
40+
41+
def __bool__(self):
42+
data_type = self.GetType()
43+
if data_type == eStructuredDataTypeInvalid:
44+
return False
45+
elif data_type in (
46+
eStructuredDataTypeArray,
47+
eStructuredDataTypeDictionary,
48+
):
49+
return self.GetSize() != 0
50+
elif data_type != eStructuredDataTypeGeneric:
51+
return bool(self.dynamic)
52+
else:
53+
raise TypeError("cannot convert generic to bool")
54+
55+
def __str__(self):
56+
data_type = self.GetType()
57+
if data_type in (
58+
eStructuredDataTypeString,
59+
eStructuredDataTypeInteger,
60+
eStructuredDataTypeSignedInteger,
61+
eStructuredDataTypeFloat,
62+
):
63+
return str(self.dynamic)
64+
else:
65+
raise TypeError(f"cannot convert {self.type_name(data_type)} to string")
66+
67+
def __int__(self):
68+
data_type = self.GetType()
69+
if data_type in (
70+
eStructuredDataTypeInteger,
71+
eStructuredDataTypeSignedInteger,
72+
):
73+
return int(self.dynamic)
74+
else:
75+
raise TypeError(f"cannot convert {self.type_name(data_type)} to int")
76+
77+
def __float__(self):
78+
data_type = self.GetType()
79+
if data_type in (
80+
eStructuredDataTypeFloat,
81+
eStructuredDataTypeInteger,
82+
eStructuredDataTypeSignedInteger,
83+
):
84+
return float(self.dynamic)
85+
else:
86+
raise TypeError(f"cannot convert {self.type_name(data_type)} to float")
87+
88+
@property
89+
def dynamic(self):
90+
data_type = self.GetType()
91+
if data_type == eStructuredDataTypeNull:
92+
return None
93+
elif data_type == eStructuredDataTypeBoolean:
94+
return self.GetBooleanValue()
95+
elif data_type == eStructuredDataTypeInteger:
96+
return self.GetUnsignedIntegerValue()
97+
elif data_type == eStructuredDataTypeSignedInteger:
98+
return self.GetSignedIntegerValue()
99+
elif data_type == eStructuredDataTypeFloat:
100+
return self.GetFloatValue()
101+
elif data_type == eStructuredDataTypeString:
102+
size = len(self) or 1023
103+
return self.GetStringValue(size + 1)
104+
elif data_type == eStructuredDataTypeGeneric:
105+
return self.GetGenericValue()
106+
else:
107+
return self
108+
109+
@staticmethod
110+
def type_name(t):
111+
if t == eStructuredDataTypeNull:
112+
return "null"
113+
elif t == eStructuredDataTypeBoolean:
114+
return "boolean"
115+
elif t == eStructuredDataTypeInteger:
116+
return "integer"
117+
elif t == eStructuredDataTypeSignedInteger:
118+
return "integer"
119+
elif t == eStructuredDataTypeFloat:
120+
return "float"
121+
elif t == eStructuredDataTypeString:
122+
return "string"
123+
elif t == eStructuredDataTypeArray:
124+
return "array"
125+
elif t == eStructuredDataTypeDictionary:
126+
return "dictionary"
127+
elif t == eStructuredDataTypeGeneric:
128+
return "generic"
129+
elif t == eStructuredDataTypeInvalid:
130+
return "invalid"
131+
else:
132+
raise TypeError(f"unknown structured data type: {t}")
16133
%}
17134
#endif
18135
}

0 commit comments

Comments
 (0)