diff --git a/module/pyjs/convert_py_to_js.py b/module/pyjs/convert_py_to_js.py index bbb4772..220570d 100644 --- a/module/pyjs/convert_py_to_js.py +++ b/module/pyjs/convert_py_to_js.py @@ -82,6 +82,11 @@ def to_js(value, cache=None, depth=0, max_depth=None): elif isinstance(value, bytes): return internal.bytes_to_typed_array(value).buffer + elif hasattr(value, "explicit_to_js"): + return value.explicit_to_js() + + elif hasattr(value, "implicit_to_js"): + return value.implicit_to_js() else: raise RuntimeError(f"no registerd converted for {value} of type {type(value)}") diff --git a/src/convert.cpp b/src/convert.cpp index 079c98d..58cb312 100644 --- a/src/convert.cpp +++ b/src/convert.cpp @@ -17,6 +17,7 @@ namespace pyjs // py::module_ pyjs = py::module_::import("pyjs_utils"); // const std::string info = pyjs.attr("implicit_convert_info")(py_ret).cast(); + const std::string info = py_ret.get_type().attr("__name__").str(); if (info == "int") @@ -47,6 +48,11 @@ namespace pyjs { return std::make_pair(em::val::module_property("_future_to_promise")(em::val(py_ret)),false); } + else if(py::hasattr(py_ret,"implicit_to_js")){ + auto implicit_to_js = py_ret.attr("implicit_to_js"); + py::object py_js_ret = implicit_to_js(); + return std::make_pair(py_js_ret.cast(),false); + } else { return std::make_pair(em::val::module_property("make_proxy")(em::val(py_ret)),true); diff --git a/src/js_timestamp.cpp b/src/js_timestamp.cpp index 0b594b1..f97153d 100644 --- a/src/js_timestamp.cpp +++ b/src/js_timestamp.cpp @@ -1 +1 @@ -#define PYJS_JS_UTC_TIMESTAMP "2024-10-18 09:14:27.486802" \ No newline at end of file +#define PYJS_JS_UTC_TIMESTAMP "2025-07-03 10:11:09.123464" \ No newline at end of file diff --git a/tests/tests/test_pyjs.py b/tests/tests/test_pyjs.py index 11154dc..8842280 100644 --- a/tests/tests/test_pyjs.py +++ b/tests/tests/test_pyjs.py @@ -376,6 +376,74 @@ def rectangle_converter(js_val, depth, cache, converter_options): assert r.width == 20 +def test_custom_implicit_converter(): + + class Foo(object): + def __init__(self, value): + + self.the_value = -1 + self.value = value + + def implicit_to_js(self): + obj = pyjs.js_object() + obj["the_value"] = self.value + return obj + + class Bar(object): + def __init__(self, value): + self.value = value + self.the_value = -1 + + def explicit_to_js(self): + obj = pyjs.js_object() + obj["the_value"] = self.value + return obj + + class FooBarInstance(object): + def __init__(self, value): + self.value = value + self.the_explicit_value = -1 + self.the_implicit_value = -1 + + def explicit_to_js(self): + obj = pyjs.js_object() + obj["the_explicit_value"] = self.value + return obj + + def implicit_to_js(self): + obj = pyjs.js_object() + obj["the_implicit_value"] = self.value + return obj + + + + foo_instance = Foo(42) + js_function = pyjs.js.Function("instance", """ + return instance.the_value === 42; + """) + assert js_function(foo_instance) is True + assert js_function(pyjs.to_js(foo_instance)) is True + + bar_instance = Bar(42) + assert js_function(bar_instance) is False + assert js_function(pyjs.to_js(bar_instance)) is True + + foo_bar_instance = FooBarInstance(42) + js_function = pyjs.js.Function("instance", """ + return instance.the_implicit_value === 42; + """) + assert js_function(foo_bar_instance) is True + assert js_function(pyjs.to_js(foo_bar_instance)) is False + + js_function = pyjs.js.Function("instance", """ + return instance.the_explicit_value === 42; + """) + assert js_function(foo_bar_instance) is False + assert js_function(pyjs.to_js(foo_bar_instance)) is True + + + + def test_del_attr(): obj = eval_jsfunc( """{