Skip to content

Commit bb8b67f

Browse files
committed
Improve handling of unsuported properties&methods in bindings, enable support for virtual methods in bindings
1 parent c17ef52 commit bb8b67f

File tree

4 files changed

+64
-39
lines changed

4 files changed

+64
-39
lines changed

generation/bindings_templates/class.tmpl.pyx

+8
Original file line numberDiff line numberDiff line change
@@ -250,12 +250,20 @@ TODO: see PinJoint.params/bias for a good example
250250

251251
@property
252252
def {{ prop.name }}(self):
253+
{% if prop.is_supported %}
253254
return self.{{ prop.getter }}({% if prop.index is not none %}{{ prop.index }}{% endif %})
255+
{% else %}
256+
raise NotImplementedError("{{prop.unsupported_reason}}")
257+
{% endif %}
254258

255259
{% if prop.setter %}
256260
@{{ prop.name }}.setter
257261
def {{ prop.name }}(self, val):
262+
{% if prop.is_supported %}
258263
self.{{ prop.setter }}({% if prop.index is not none %}{{ prop.index }},{% endif %}val)
264+
{% else %}
265+
raise NotImplementedError("{{prop.unsupported_reason}}")
266+
{% endif %}
259267
{% endif %}
260268

261269
{% endfor %}

generation/bindings_templates/method.tmpl.pyx

+4
Original file line numberDiff line numberDiff line change
@@ -147,8 +147,12 @@ with nogil:
147147
{% macro render_method(cls, method) %}
148148
# {{ render_method_c_signature(method) }}
149149
def {{ render_method_signature(method) }}:
150+
{% if method.is_supported %}
150151
{{ _render_method_cook_args(method) | indent }}
151152
{{ _render_method_call(cls, method) | indent }}
152153
{{ _render_method_destroy_args(method) | indent }}
153154
{{ _render_method_return(method) | indent }}
155+
{% else %}
156+
raise NotImplementedError("{{method.unsupported_reason}}")
157+
{% endif %}
154158
{% endmacro %}

generation/generate_bindings.py

+37-39
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,13 @@ class PropertyInfo:
2626
setter: str
2727
index: Optional[int]
2828

29+
# If using feature we don't support yet
30+
unsupported_reason: Optional[str] = None
31+
32+
@property
33+
def is_supported(self) -> bool:
34+
return self.unsupported_reason is None
35+
2936

3037
@dataclass
3138
class ArgumentInfo:
@@ -43,6 +50,13 @@ class SignalInfo:
4350
name: str
4451
arguments: List[ArgumentInfo]
4552

53+
# If using feature we don't support yet
54+
unsupported_reason: Optional[str] = None
55+
56+
@property
57+
def is_supported(self) -> bool:
58+
return self.unsupported_reason is None
59+
4660

4761
@dataclass
4862
class MethodInfo:
@@ -57,6 +71,13 @@ class MethodInfo:
5771
is_from_script: bool
5872
arguments: List[ArgumentInfo]
5973

74+
# If using feature we don't support yet
75+
unsupported_reason: Optional[str] = None
76+
77+
@property
78+
def is_supported(self) -> bool:
79+
return self.unsupported_reason is None
80+
6081

6182
@dataclass
6283
class EnumInfo:
@@ -240,66 +261,43 @@ def _is_supported_type(specs):
240261
else:
241262
return True
242263

243-
kept_classes = []
244264
for klass in classes:
245-
methods = []
246265
for meth in klass.methods:
266+
unsupported_reason = None
247267
# TODO: handle default param values
248268
# TODO: handle those flags
249269
if meth.is_editor:
250-
# warn(f"Ignoring `{klass.name}.{meth.name}` (attribute `is_editor=True` not supported)")
251-
continue
270+
unsupported_reason = "attribute `is_editor=True` not supported"
252271
if meth.is_reverse:
253-
warn(
254-
f"Ignoring `{klass.name}.{meth.name}` (attribute `is_reverse=True` not supported)"
255-
)
256-
continue
257-
if meth.is_virtual:
258-
# warn(f"Ignoring `{klass.name}.{meth.name}` (attribute `is_virtual=True` not supported)")
259-
continue
272+
unsupported_reason = "attribute `is_reverse=True` not supported"
260273
if meth.has_varargs:
261-
# warn(f"Ignoring `{klass.name}.{meth.name}` (attribute `has_varargs=True` not supported)")
262-
continue
274+
unsupported_reason = "attribute `has_varargs=True` not supported"
263275
if not _is_supported_type(meth.return_type):
264-
warn(
265-
f"Ignoring `{klass.name}.{meth.name}` (return type {meth.return_type} not supported)"
266-
)
267-
continue
276+
unsupported_reason = f"return type {meth.return_type} not supported"
268277
bad_arg = next(
269278
(arg for arg in meth.arguments if not _is_supported_type(arg.type)), None
270279
)
271280
if bad_arg:
272-
warn(f"Ignoring `{klass.name}.{meth.name}` (argument type {bad_arg} not supported)")
273-
continue
274-
methods.append(meth)
275-
klass.methods = methods
281+
unsupported_reason = f"argument type {bad_arg} not supported"
282+
283+
if unsupported_reason:
284+
warn(f"Ignoring `{klass.name}.{meth.name}` ({unsupported_reason})")
285+
meth.unsupported_reason = unsupported_reason
276286

277-
properties = []
278287
for prop in klass.properties:
279288
if not _is_supported_type(prop.type):
280-
warn(
281-
f"Ignoring property `{klass.name}.{prop.name}` (property type {prop.type} not supported)"
282-
)
283-
continue
284-
properties.append(prop)
285-
klass.properties = properties
289+
unsupported_reason = f"property type {prop.type} not supported"
290+
warn(f"Ignoring property `{klass.name}.{prop.name}` ({unsupported_reason})")
291+
prop.unsupported_reason = unsupported_reason
286292

287-
signals = []
288293
for signal in klass.signals:
289294
bad_arg = next(
290295
(arg for arg in signal.arguments if not _is_supported_type(arg.type)), None
291296
)
292297
if bad_arg:
293-
warn(
294-
f"Ignoring signal `{klass.name}.{signal.name}` (argument type {bad_arg} not supported)"
295-
)
296-
continue
297-
signals.append(signal)
298-
klass.signals = signals
299-
300-
kept_classes.append(klass)
301-
302-
return kept_classes
298+
unsupported_reason = f"argument type {bad_arg} not supported"
299+
warn(f"Ignoring signal `{klass.name}.{signal.name}` ({unsupported_reason})")
300+
signal.unsupported_reason = unsupported_reason
303301

304302

305303
def strip_sample_stuff(classes):

tests/bindings/test_bindings.py

+15
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,8 @@
55
import godot
66
from godot import (
77
Vector3,
8+
GDString,
9+
NodePath,
810
Object,
911
Node,
1012
CanvasItem,
@@ -156,6 +158,19 @@ def test_call_with_refcounted_param_value(generate_obj):
156158
node.set_script(script)
157159

158160

161+
def test_access_property(generate_obj):
162+
node = generate_obj(Node)
163+
path = NodePath("/foo/bar")
164+
node._import_path = path
165+
assert node._import_path == path
166+
167+
168+
def test_call_virtual(generate_obj):
169+
node = generate_obj(Node)
170+
ret = node._to_string()
171+
assert isinstance(ret, GDString)
172+
173+
159174
def test_create_refcounted_value(current_node):
160175
script1_ref1 = PluginScript()
161176
script2_ref1 = PluginScript()

0 commit comments

Comments
 (0)