From ef9d73f178fdaf073fdcd8d17b1776d4aa1a2b77 Mon Sep 17 00:00:00 2001 From: Matthias Koefferlein Date: Sun, 26 Nov 2023 00:31:07 +0100 Subject: [PATCH] Experimental: calling str(x) implicitly in RBA and pya --- src/pya/pya/pyaMarshal.cc | 21 +++++++++++++++++++-- src/rba/rba/rbaMarshal.cc | 2 +- testdata/python/basic.py | 16 +++++++++------- testdata/ruby/basic_testcore.rb | 30 +++++++++++++++++------------- 4 files changed, 46 insertions(+), 23 deletions(-) diff --git a/src/pya/pya/pyaMarshal.cc b/src/pya/pya/pyaMarshal.cc index 0d1274d6cf..a75bd393bd 100644 --- a/src/pya/pya/pyaMarshal.cc +++ b/src/pya/pya/pyaMarshal.cc @@ -43,9 +43,26 @@ class PythonBasedStringAdaptor { public: PythonBasedStringAdaptor (const PythonPtr &string) - : m_stdstr (python2c (string.get ())), m_string (string) + : m_string (string) { - // .. nothing yet .. +#if PY_MAJOR_VERSION < 3 + if (PyString_Check (string.get ())) { + m_stdstr = python2c (string.get ()); + } else +#else + if (PyBytes_Check (string.get ())) { + m_stdstr = python2c (string.get ()); + } else +#endif + if (PyUnicode_Check (string.get ()) || PyByteArray_Check (string.get ())) { + m_stdstr = python2c (string.get ()); + } else { + // use object protocol to get the string through str(...) + PythonRef as_str (PyObject_Str (string.get ())); + if (as_str) { + m_stdstr = python2c (as_str.get ()); + } + } } virtual const char *c_str () const diff --git a/src/rba/rba/rbaMarshal.cc b/src/rba/rba/rbaMarshal.cc index 7478ecbc2b..b0079bc8e4 100644 --- a/src/rba/rba/rbaMarshal.cc +++ b/src/rba/rba/rbaMarshal.cc @@ -46,7 +46,7 @@ class RubyBasedStringAdaptor public: RubyBasedStringAdaptor (VALUE value) { - m_string = rba_safe_string_value (value); + m_string = rba_safe_obj_as_string (value); gc_lock_object (m_string); } diff --git a/testdata/python/basic.py b/testdata/python/basic.py index 3c64efbb79..5e3e13de9f 100644 --- a/testdata/python/basic.py +++ b/testdata/python/basic.py @@ -26,6 +26,12 @@ # Set this to True to disable some tests involving exceptions leak_check = "TEST_LEAK_CHECK" in os.environ +class ObjectWithStr: + def __init__(self, s): + self.s = s + def __str__(self): + return self.s + # see test_21 class AEXT(pya.A): def __init__(self): @@ -191,6 +197,7 @@ def test_00(self): self.assertEqual( a.a1(), -0x80000000 ) self.assertEqual( a.a3("a"), 1 ) + self.assertEqual( a.a3(ObjectWithStr("abcde")), 5 ) # implicitly using to_s for string conversion self.assertEqual( a.a3("ab"), 2 ) self.assertEqual( a.a3("µ"), 2 ) # two UTF8 bytes if "a3_qstr" in a.__dict__: @@ -2279,13 +2286,8 @@ def test_41(self): self.assertEqual(b.map1_cptr_null() == None, True); self.assertEqual(b.map1_ptr_null() == None, True); - try: - # error converting 1 or True to string - b.map1 = { 42: 1, -17: True } - error_caught = False - except: - error_caught = True - self.assertEqual(error_caught, True) + b.map1 = { 42: 1, -17: True } + self.assertEqual(map2str(b.map1), "{-17: True, 42: 1}") b.map1 = { 42: "1", -17: "True" } self.assertEqual(map2str(b.map1), "{-17: True, 42: 1}") diff --git a/testdata/ruby/basic_testcore.rb b/testdata/ruby/basic_testcore.rb index 87f2f1e4be..04ce765056 100644 --- a/testdata/ruby/basic_testcore.rb +++ b/testdata/ruby/basic_testcore.rb @@ -4,6 +4,19 @@ # safe in multiple inclusions require File.expand_path('../basic_testcore_defs', __FILE__) + +class ObjectWithStr + + def initialize(s) + @s = s + end + + def to_s + @s + end + +end + class Basic_TestClass < TestBase def test_FIRST @@ -85,6 +98,7 @@ def test_FIRST assert_equal( a.a1, -0x80000000 ) assert_equal( a.a3("a"), 1 ) + assert_equal( a.a3(ObjectWithStr::new("abcde")), 5 ) # implicitly using to_s for string conversion assert_equal( a.a3("ab"), 2 ) assert_equal( a.a3("µ"), 2 ) # two UTF8 bytes if a.respond_to?(:a3_qstr) @@ -2198,19 +2212,9 @@ def test_41 assert_equal(b.map1_cptr_null == nil, true); assert_equal(b.map1_ptr_null == nil, true); - begin - b.map1 = { 42 => 1, -17 => true } - error = nil - rescue => ex - error = ex.message.split("\n")[0] - end - if error == "can't convert Fixnum into String" - # Ok - elsif error == "no implicit conversion of Fixnum into String" || error == "no implicit conversion of Integer into String" - # Ok - else - assert_equal(error, "") - end + b.map1 = { 42 => 1, -17 => true } + assert_equal(b.map1.inspect, "{-17=>\"true\", 42=>\"1\"}") + b.map1 = { 42 => "1", -17 => "true" } assert_equal(b.map1.inspect, "{-17=>\"true\", 42=>\"1\"}")