doxysip 0.1__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.
- doxysip/__init__.py +53 -0
- doxysip/combiner.py +456 -0
- doxysip/directives.py +735 -0
- doxysip/dox_struct.py +435 -0
- doxysip/sip_struct.py +487 -0
- doxysip-0.1.dist-info/METADATA +86 -0
- doxysip-0.1.dist-info/RECORD +10 -0
- doxysip-0.1.dist-info/WHEEL +5 -0
- doxysip-0.1.dist-info/licenses/LICENSE +28 -0
- doxysip-0.1.dist-info/top_level.txt +1 -0
doxysip/__init__.py
ADDED
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
# SPDX-License-Identifier: BSD-3-Clause
|
|
2
|
+
|
|
3
|
+
# Copyright (c) 2026 C. Savergne <csavergne@yahoo.com>
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
from sphinx.domains import Domain
|
|
7
|
+
|
|
8
|
+
from .directives import (
|
|
9
|
+
SIPSpecificationDirective,
|
|
10
|
+
SIPModuleDirective,
|
|
11
|
+
SIPClassDirective,
|
|
12
|
+
SIPNamespaceDirective,
|
|
13
|
+
SIPEnumDirective,
|
|
14
|
+
SIPMethodDirective,
|
|
15
|
+
SIPPropertyDirective,
|
|
16
|
+
SIPVariableDirective,
|
|
17
|
+
SIPMacroConstantDirective,
|
|
18
|
+
)
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
__version__ = "0.0.1"
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
class SIPDomain(Domain):
|
|
25
|
+
name = 'sip'
|
|
26
|
+
label = 'Bindings specification language'
|
|
27
|
+
directives = {
|
|
28
|
+
'specification': SIPSpecificationDirective,
|
|
29
|
+
'module' : SIPModuleDirective,
|
|
30
|
+
'class': SIPClassDirective,
|
|
31
|
+
'namespace': SIPNamespaceDirective,
|
|
32
|
+
'enum': SIPEnumDirective,
|
|
33
|
+
'method': SIPMethodDirective,
|
|
34
|
+
'property': SIPPropertyDirective,
|
|
35
|
+
'variable': SIPVariableDirective,
|
|
36
|
+
'macro-constant': SIPMacroConstantDirective,
|
|
37
|
+
}
|
|
38
|
+
initial_data = {
|
|
39
|
+
'sip_specs': {},
|
|
40
|
+
'sip_dox_index': None,
|
|
41
|
+
'sip_project_loaded': False,
|
|
42
|
+
'sip_current_spec': '',
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
|
|
46
|
+
def setup(app):
|
|
47
|
+
app.add_domain(SIPDomain)
|
|
48
|
+
app.add_config_value('sip_toml_project', '.', 'env', str)
|
|
49
|
+
app.add_config_value('sip_doxygen_project', '.', 'env', str)
|
|
50
|
+
|
|
51
|
+
return {
|
|
52
|
+
"version": __version__
|
|
53
|
+
}
|
doxysip/combiner.py
ADDED
|
@@ -0,0 +1,456 @@
|
|
|
1
|
+
# SPDX-License-Identifier: BSD-3-Clause
|
|
2
|
+
|
|
3
|
+
# Copyright (c) 2026 C. Savergne <csavergne@yahoo.com>
|
|
4
|
+
|
|
5
|
+
import dataclasses
|
|
6
|
+
|
|
7
|
+
from . import sip_struct
|
|
8
|
+
from . import dox_struct
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
def _get_dox_index(domain):
|
|
12
|
+
dox_dir = domain.env.app.config.sip_doxygen_project
|
|
13
|
+
dox_dir = os.path.abspath(dox_dir)
|
|
14
|
+
|
|
15
|
+
dox_index = domain.data['sip_dox_index']
|
|
16
|
+
if dox_index is None:
|
|
17
|
+
index_path = os.path.join(dox_dir, 'index.xml')
|
|
18
|
+
dox_index = xml_parse(index_path)
|
|
19
|
+
domain.data['sip_dox_index'] = dox_index
|
|
20
|
+
|
|
21
|
+
return dox_struct.DoxElement(dox_index.documentElement)
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
def find_dox_for_sip_class(spec, domain, sip_klass):
|
|
25
|
+
dox_index = _get_dox_index(domain)
|
|
26
|
+
|
|
27
|
+
if sip_klass.scope is None:
|
|
28
|
+
for node in root.find_children('compound'):
|
|
29
|
+
if sip_klass.class_key is None:
|
|
30
|
+
if node.attr('kind') != 'namespace': continue
|
|
31
|
+
else:
|
|
32
|
+
if node.attr('kind') not in ('class', 'struct'): continue
|
|
33
|
+
|
|
34
|
+
sip_scoped_name = sip_klass.iface_file.fq_cpp_name
|
|
35
|
+
|
|
36
|
+
|
|
37
|
+
refid = node.attr('refid')
|
|
38
|
+
fn = os.path.join(dox_dir, refid + '.xml')
|
|
39
|
+
klass_xmldoc = xml_parse(fn)
|
|
40
|
+
|
|
41
|
+
element = DoxElement(klass_xmldoc.documentElement)
|
|
42
|
+
return element.find_child('compounddef')
|
|
43
|
+
|
|
44
|
+
return None
|
|
45
|
+
|
|
46
|
+
|
|
47
|
+
def _find_dox_member_by_kind(dox_klass, kind, predicate=None):
|
|
48
|
+
member = None
|
|
49
|
+
if dox_klass is not None:
|
|
50
|
+
for m in dox_klass.getElementsByTagName('memberdef'):
|
|
51
|
+
if m.attr('kind') != kind: continue
|
|
52
|
+
if predicate is not None and not predicate(m): continue
|
|
53
|
+
#if member is not None:
|
|
54
|
+
# raise ValueError('Multiple member match')
|
|
55
|
+
member = m
|
|
56
|
+
|
|
57
|
+
return member
|
|
58
|
+
|
|
59
|
+
|
|
60
|
+
|
|
61
|
+
SLOT_MAPPING = {
|
|
62
|
+
'or': '|',
|
|
63
|
+
'and': '&',
|
|
64
|
+
'xor': '^',
|
|
65
|
+
'invert': '~',
|
|
66
|
+
'add': '+',
|
|
67
|
+
'sub': '-',
|
|
68
|
+
'mul': '*',
|
|
69
|
+
'truediv': '/',
|
|
70
|
+
'mod': '%',
|
|
71
|
+
'pos': '+',
|
|
72
|
+
'neg': '-',
|
|
73
|
+
'lshift': '<<',
|
|
74
|
+
'rshift': '>>',
|
|
75
|
+
'ior': '|=',
|
|
76
|
+
'iand': '&=',
|
|
77
|
+
'ixor': '^=',
|
|
78
|
+
'iadd': '+=',
|
|
79
|
+
'isub': '-=',
|
|
80
|
+
'imul': '*=',
|
|
81
|
+
'itruediv': '/=',
|
|
82
|
+
'imod': '%=',
|
|
83
|
+
'ilshift': '<<=',
|
|
84
|
+
'irshift': '>>=',
|
|
85
|
+
'call': '()',
|
|
86
|
+
'getitem': '[]',
|
|
87
|
+
'eq': '==',
|
|
88
|
+
'ne': '!=',
|
|
89
|
+
'lt': '<',
|
|
90
|
+
'le': '<=',
|
|
91
|
+
'gt': '>',
|
|
92
|
+
'ge': '>=',
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
def _py_slot_to_cpp_name(py_slot_name):
|
|
96
|
+
py_name = py_slot_name.strip('_')
|
|
97
|
+
cpp_op = SLOT_MAPPING.get(py_name, None)
|
|
98
|
+
if cpp_op is None:
|
|
99
|
+
return None
|
|
100
|
+
return 'operator' + cpp_op
|
|
101
|
+
|
|
102
|
+
|
|
103
|
+
_TAG_MARKER = '\\dox:'
|
|
104
|
+
|
|
105
|
+
def _parse_docstring(docstring):
|
|
106
|
+
'''Parse the docstring and extract the marker if present and
|
|
107
|
+
leave the rest of the docstring unchanged
|
|
108
|
+
'''
|
|
109
|
+
|
|
110
|
+
if docstring is None:
|
|
111
|
+
return '', None
|
|
112
|
+
|
|
113
|
+
if not docstring.text:
|
|
114
|
+
return '', []
|
|
115
|
+
|
|
116
|
+
tag = ''
|
|
117
|
+
ds_lines = docstring.text.strip(' \t\r\n').split('\n')
|
|
118
|
+
headlines = True
|
|
119
|
+
textlines = []
|
|
120
|
+
for line in ds_lines:
|
|
121
|
+
if headlines and line.startswith(_TAG_MARKER):
|
|
122
|
+
tag = line.replace(_TAG_MARKER, '').lstrip()
|
|
123
|
+
else:
|
|
124
|
+
headlines = False
|
|
125
|
+
textlines.append(line)
|
|
126
|
+
|
|
127
|
+
return tag, textlines
|
|
128
|
+
|
|
129
|
+
|
|
130
|
+
def merge_description(sip_docstring, dox_node):
|
|
131
|
+
tag, sip_desc = _parse_docstring(sip_docstring)
|
|
132
|
+
|
|
133
|
+
if dox_node is None:
|
|
134
|
+
dox_desc = ''
|
|
135
|
+
else:
|
|
136
|
+
dox_desc = dox_struct.extract_description(dox_node)
|
|
137
|
+
|
|
138
|
+
if sip_desc is None:
|
|
139
|
+
if dox_desc:
|
|
140
|
+
merged_desc = dox_desc
|
|
141
|
+
else:
|
|
142
|
+
merged_desc = None
|
|
143
|
+
else:
|
|
144
|
+
if dox_desc:
|
|
145
|
+
if tag == 'prepend':
|
|
146
|
+
merged_desc = dox_desc + [''] + sip_desc
|
|
147
|
+
elif tag == 'append':
|
|
148
|
+
merged_desc = sip_desc + [''] + dox_desc
|
|
149
|
+
else: #discard
|
|
150
|
+
merged_desc = sip_desc
|
|
151
|
+
else:
|
|
152
|
+
merged_desc = sip_desc
|
|
153
|
+
|
|
154
|
+
return tag, merged_desc
|
|
155
|
+
|
|
156
|
+
|
|
157
|
+
#==============================================================================
|
|
158
|
+
|
|
159
|
+
@dataclasses.dataclass
|
|
160
|
+
class FunctionDeclaration:
|
|
161
|
+
|
|
162
|
+
name: str|None = None #not for constructors
|
|
163
|
+
signature: str = ''
|
|
164
|
+
description: str|None = None
|
|
165
|
+
arguments: list[tuple[str, str|None]] = dataclasses.field(default_factory=list)
|
|
166
|
+
result: str|None = None
|
|
167
|
+
default: bool = False #for constructors only
|
|
168
|
+
|
|
169
|
+
@property
|
|
170
|
+
def documented(self):
|
|
171
|
+
return self.description is not None or \
|
|
172
|
+
any(a[1] is not None for a in self.arguments) or \
|
|
173
|
+
self.result is not None
|
|
174
|
+
|
|
175
|
+
|
|
176
|
+
def _combine_arguments(sip_signature, dox_member, discard_no_desc):
|
|
177
|
+
#Extract the argument declared names from the param nodes
|
|
178
|
+
if dox_member is not None:
|
|
179
|
+
dox_arg_declnames = [ n.child_text('declname') for n in dox_member.find_children('param')]
|
|
180
|
+
|
|
181
|
+
#Extract the argument name and description node from the \param tags in the comment
|
|
182
|
+
dox_arg_desc_map = {}
|
|
183
|
+
for n_arg_list in dox_member.getElementsByTagName('parameterlist'):
|
|
184
|
+
if n_arg_list.attr('kind') != 'param': continue
|
|
185
|
+
for n_arg_name, n_arg_desc in zip(n_arg_list.getElementsByTagName('parameternamelist'),
|
|
186
|
+
n_arg_list.getElementsByTagName('parameterdescription'),
|
|
187
|
+
strict=True):
|
|
188
|
+
name = n_arg_name.child_text('parametername')
|
|
189
|
+
dox_arg_desc_map[name] = n_arg_desc
|
|
190
|
+
|
|
191
|
+
else:
|
|
192
|
+
dox_arg_declnames = []
|
|
193
|
+
dox_arg_desc_map = {}
|
|
194
|
+
|
|
195
|
+
#Combine the argument metadata from sip and dox into arg_descriptions
|
|
196
|
+
arg_descriptions = []
|
|
197
|
+
for ix, sip_arg in enumerate(sip_signature.args):
|
|
198
|
+
#Replace the argument name in SIP if it's empty
|
|
199
|
+
if sip_arg.name is not None:
|
|
200
|
+
arg_name = sip_arg.name.name
|
|
201
|
+
elif ix < len(dox_arg_declnames):
|
|
202
|
+
arg_name = dox_arg_declnames[ix]
|
|
203
|
+
if arg_name is not None:
|
|
204
|
+
#Modify the signature to let the name appear
|
|
205
|
+
sip_arg.name = sip_struct.CachedName(arg_name)
|
|
206
|
+
else:
|
|
207
|
+
arg_name = None
|
|
208
|
+
|
|
209
|
+
if arg_name is not None:
|
|
210
|
+
dox_arg_desc_node = dox_arg_desc_map.get(arg_name, None)
|
|
211
|
+
if dox_arg_desc_node is not None:
|
|
212
|
+
arg_desc = dox_struct.extract_single_line_description(dox_arg_desc_node)
|
|
213
|
+
arg_descriptions.append((arg_name, arg_desc))
|
|
214
|
+
elif not discard_no_desc:
|
|
215
|
+
arg_descriptions.append((arg_name, None))
|
|
216
|
+
|
|
217
|
+
return arg_descriptions
|
|
218
|
+
|
|
219
|
+
|
|
220
|
+
def combine_constructors(sip_spec, sip_klass, dox_klass):
|
|
221
|
+
|
|
222
|
+
klass_name = sip_klass.py_name.name
|
|
223
|
+
|
|
224
|
+
def ctor_match(ctor, m):
|
|
225
|
+
|
|
226
|
+
if m.child_text('name') != dox_klass.child_text('compoundname'):
|
|
227
|
+
return False
|
|
228
|
+
|
|
229
|
+
dox_arg_sig = dox_struct.get_fct_arg_signature(m)
|
|
230
|
+
if ctor.cpp_arg_signature != dox_arg_sig:
|
|
231
|
+
return False
|
|
232
|
+
|
|
233
|
+
return True
|
|
234
|
+
|
|
235
|
+
ctor_decl_list = []
|
|
236
|
+
for sip_ctor in sip_klass.ctors:
|
|
237
|
+
if sip_ctor.access_specifier is sip_struct.AccessSpecifier.PRIVATE: continue
|
|
238
|
+
|
|
239
|
+
ctor = sip_struct.SIP_Constructor(sip_spec, sip_klass, sip_ctor)
|
|
240
|
+
|
|
241
|
+
ctor_decl = FunctionDeclaration()
|
|
242
|
+
|
|
243
|
+
#Find the corresponding member node
|
|
244
|
+
dox_ctor = _find_dox_member_by_kind(dox_klass, 'function', lambda m: ctor_match(ctor, m))
|
|
245
|
+
|
|
246
|
+
#Description for the overload
|
|
247
|
+
tag, merged_description = merge_description(ctor.docstring, dox_ctor)
|
|
248
|
+
ctor_decl.description = merged_description
|
|
249
|
+
|
|
250
|
+
#Try to fill in the missing argument name and description using Doxygen
|
|
251
|
+
#Skip it if there is a docstring with a 'discard' tag
|
|
252
|
+
ctor_decl.arguments = _combine_arguments(ctor.py_signature,
|
|
253
|
+
dox_ctor if tag != 'discard' else None,
|
|
254
|
+
ctor.docstring is not None)
|
|
255
|
+
|
|
256
|
+
arg_sig = sip_struct.fmt_signature_as_type_hint(sip_spec,
|
|
257
|
+
ctor.py_signature,
|
|
258
|
+
need_self=False,
|
|
259
|
+
defined=None)
|
|
260
|
+
ctor_decl.signature = f'{klass_name}{arg_sig}'
|
|
261
|
+
ctor_decl.default = ctor.is_default
|
|
262
|
+
ctor_decl_list.append(ctor_decl)
|
|
263
|
+
|
|
264
|
+
return ctor_decl_list
|
|
265
|
+
|
|
266
|
+
|
|
267
|
+
def combine_overload(sip_spec, overload, dox_klass):
|
|
268
|
+
|
|
269
|
+
if overload.py_slot:
|
|
270
|
+
sip_cpp_name = _py_slot_to_cpp_name(overload.py_name)
|
|
271
|
+
else:
|
|
272
|
+
sip_cpp_name = overload.cpp_name
|
|
273
|
+
|
|
274
|
+
|
|
275
|
+
def overload_match(m):
|
|
276
|
+
|
|
277
|
+
dox_name = m.child_text('name')
|
|
278
|
+
if sip_cpp_name != dox_name:
|
|
279
|
+
return False
|
|
280
|
+
if overload.is_const != (m.attr('const') == 'yes'):
|
|
281
|
+
return False
|
|
282
|
+
if overload.is_static != (m.attr('static') == 'yes'):
|
|
283
|
+
return False
|
|
284
|
+
|
|
285
|
+
dox_result_sig = dox_struct.get_type_signature(m.find_child('type'))
|
|
286
|
+
if overload.result_signature != dox_result_sig:
|
|
287
|
+
return False
|
|
288
|
+
|
|
289
|
+
dox_arg_sig = dox_struct.get_fct_arg_signature(m)
|
|
290
|
+
if overload.cpp_arg_signature != dox_arg_sig:
|
|
291
|
+
return False
|
|
292
|
+
|
|
293
|
+
return True
|
|
294
|
+
|
|
295
|
+
#Find the corresponding member node
|
|
296
|
+
dox_member = _find_dox_member_by_kind(dox_klass, 'function', overload_match)
|
|
297
|
+
|
|
298
|
+
fct_decl = FunctionDeclaration(name=overload.py_name)
|
|
299
|
+
|
|
300
|
+
#Description for the overload
|
|
301
|
+
tag, overload_description = merge_description(overload.docstring, dox_member)
|
|
302
|
+
fct_decl.description = overload_description
|
|
303
|
+
|
|
304
|
+
#Find the argument and result descriptions. Skip if the tag is 'discard'
|
|
305
|
+
if tag != 'discard':
|
|
306
|
+
fct_decl.arguments = _combine_arguments(overload.py_signature,
|
|
307
|
+
dox_member,
|
|
308
|
+
overload.docstring is not None)
|
|
309
|
+
if dox_member is not None:
|
|
310
|
+
#Find the description of the return value
|
|
311
|
+
for n in dox_member.getElementsByTagName('simplesect'):
|
|
312
|
+
if n.attr('kind') != 'return': continue
|
|
313
|
+
fct_decl.result = dox_struct.extract_single_line_description(n)
|
|
314
|
+
break
|
|
315
|
+
else:
|
|
316
|
+
fct_decl.arguments = _combine_arguments(overload.py_signature, None, True)
|
|
317
|
+
|
|
318
|
+
arg_sig = sip_struct.fmt_signature_as_type_hint(sip_spec,
|
|
319
|
+
overload.py_signature,
|
|
320
|
+
need_self=False,
|
|
321
|
+
defined=None)
|
|
322
|
+
fct_decl.signature = f'{overload.py_name}{arg_sig}'
|
|
323
|
+
|
|
324
|
+
return fct_decl
|
|
325
|
+
|
|
326
|
+
|
|
327
|
+
#==============================================================================
|
|
328
|
+
|
|
329
|
+
@dataclasses.dataclass
|
|
330
|
+
class EnumDeclaration:
|
|
331
|
+
signature: str
|
|
332
|
+
description: str|None
|
|
333
|
+
members: list[tuple[str, str|None]]|None
|
|
334
|
+
|
|
335
|
+
|
|
336
|
+
def combine_enum(sip_enum, dox_enum):
|
|
337
|
+
superclass = 'int'
|
|
338
|
+
if sip_enum.base_type is sip_struct.EnumBaseType.ENUM:
|
|
339
|
+
superclass = 'enum.Enum'
|
|
340
|
+
elif sip_enum.base_type is sip_struct.EnumBaseType.FLAG:
|
|
341
|
+
superclass = 'enum.Flag'
|
|
342
|
+
elif sip_enum.base_type in (sip_struct.EnumBaseType.INT_ENUM, sip_struct.EnumBaseType.UINT_ENUM):
|
|
343
|
+
superclass = 'enum.IntEnum'
|
|
344
|
+
elif sip_enum.base_type is sip_struct.EnumBaseType.INT_FLAG:
|
|
345
|
+
superclass = 'enum.IntFlag'
|
|
346
|
+
|
|
347
|
+
sig = f'{sip_enum.py_name} ({superclass})'
|
|
348
|
+
|
|
349
|
+
if dox_enum is None:
|
|
350
|
+
enum_desc = None
|
|
351
|
+
else:
|
|
352
|
+
enum_desc = dox_struct.extract_description(dox_enum)
|
|
353
|
+
|
|
354
|
+
members_decl = []
|
|
355
|
+
for member in sip_enum.members:
|
|
356
|
+
desc = None
|
|
357
|
+
if dox_enum is not None:
|
|
358
|
+
for dox_enum_value in dox_enum.find_children('enumvalue'):
|
|
359
|
+
if dox_enum_value.child_text('name') == member.cpp_name:
|
|
360
|
+
desc = dox_struct.extract_description(dox_enum_value)
|
|
361
|
+
break
|
|
362
|
+
members_decl.append((member.py_name.name, desc))
|
|
363
|
+
|
|
364
|
+
return EnumDeclaration(sig, enum_desc, members_decl)
|
|
365
|
+
|
|
366
|
+
|
|
367
|
+
def combine_class_enum(sip_enum, dox_klass):
|
|
368
|
+
enum_cpp_name = sip_enum.fq_cpp_name.base_name
|
|
369
|
+
enum_match = lambda m : m.child_text('name') == enum_cpp_name
|
|
370
|
+
dox_enum = _find_dox_member_by_kind(dox_klass, 'enum', enum_match)
|
|
371
|
+
return combine_enum(sip_enum, dox_enum)
|
|
372
|
+
|
|
373
|
+
|
|
374
|
+
#==============================================================================
|
|
375
|
+
|
|
376
|
+
@dataclasses.dataclass
|
|
377
|
+
class PropertyDeclaration:
|
|
378
|
+
name: str
|
|
379
|
+
type: str|None
|
|
380
|
+
description: str|None
|
|
381
|
+
|
|
382
|
+
|
|
383
|
+
def combine_property(sip_spec, sip_klass, sip_prop):
|
|
384
|
+
getter_member = None
|
|
385
|
+
for m in sip_klass.members:
|
|
386
|
+
if m.py_name.name == sip_prop.getter:
|
|
387
|
+
getter_member = m
|
|
388
|
+
break
|
|
389
|
+
|
|
390
|
+
#Infer the property type from the getter result type
|
|
391
|
+
result_type = None
|
|
392
|
+
if getter_member:
|
|
393
|
+
c = sip_struct.SIP_Callable(sip_spec, sip_klass, getter_member)
|
|
394
|
+
for ovr in c.overloads:
|
|
395
|
+
if not len(ovr.py_signature.args):
|
|
396
|
+
result_type = sip_struct.signature_as_result_type_hint(sip_spec, ovr.py_signature)
|
|
397
|
+
break
|
|
398
|
+
|
|
399
|
+
_, description = _parse_docstring(sip_prop.docstring)
|
|
400
|
+
|
|
401
|
+
return PropertyDeclaration(sip_prop.name.name, result_type, description)
|
|
402
|
+
|
|
403
|
+
|
|
404
|
+
#==============================================================================
|
|
405
|
+
|
|
406
|
+
@dataclasses.dataclass
|
|
407
|
+
class VariableDeclaration:
|
|
408
|
+
name: str
|
|
409
|
+
type_: str
|
|
410
|
+
const: bool
|
|
411
|
+
qualifiers : list[str]
|
|
412
|
+
description : str|None
|
|
413
|
+
|
|
414
|
+
|
|
415
|
+
def combine_variable(sip_spec, sip_var, dox_var):
|
|
416
|
+
var_type = sip_struct.fmt_argument_as_type_hint(sip_spec, sip_var.type, None, None)
|
|
417
|
+
|
|
418
|
+
if dox_var is not None:
|
|
419
|
+
description = dox_struct.extract_description(dox_var)
|
|
420
|
+
else:
|
|
421
|
+
description = None
|
|
422
|
+
|
|
423
|
+
has_const_type = sip_var.type.is_const# and len(sip_var.type.derefs) == 0
|
|
424
|
+
is_const = has_const_type and (sip_var.is_static or sip_var.scope is None)
|
|
425
|
+
qualifiers = []
|
|
426
|
+
if sip_var.no_setter or has_const_type:
|
|
427
|
+
qualifiers.append('readonly')
|
|
428
|
+
if sip_var.is_static:
|
|
429
|
+
qualifiers.append('static')
|
|
430
|
+
|
|
431
|
+
var_decl = VariableDeclaration(sip_var.py_name.name,
|
|
432
|
+
var_type,
|
|
433
|
+
is_const,
|
|
434
|
+
qualifiers,
|
|
435
|
+
description)
|
|
436
|
+
|
|
437
|
+
return var_decl
|
|
438
|
+
|
|
439
|
+
|
|
440
|
+
def combine_class_variable(sip_spec, sip_var, dox_klass):
|
|
441
|
+
var_cpp_name = sip_var.fq_cpp_name.base_name
|
|
442
|
+
dox_var = _find_dox_member_by_kind(dox_klass, 'variable', lambda m: m.child_text('name') == var_cpp_name)
|
|
443
|
+
return combine_variable(sip_spec, sip_var, dox_var)
|
|
444
|
+
|
|
445
|
+
|
|
446
|
+
def combine_class_variables(sip_spec, sip_klass, dox_klass):
|
|
447
|
+
var_decl_list = []
|
|
448
|
+
for v in sip_spec.variables:
|
|
449
|
+
if v.module is not sip_spec.module: continue
|
|
450
|
+
if v.scope is not sip_klass: continue
|
|
451
|
+
|
|
452
|
+
var_decl = combine_class_variable(sip_spec, v, dox_klass)
|
|
453
|
+
var_decl_list.append(var_decl)
|
|
454
|
+
|
|
455
|
+
return var_decl_list
|
|
456
|
+
|