diff --git a/src/gsi/gsi/gsiMethods.cc b/src/gsi/gsi/gsiMethods.cc index 717ce0389..95a02b5ca 100644 --- a/src/gsi/gsi/gsiMethods.cc +++ b/src/gsi/gsi/gsiMethods.cc @@ -195,7 +195,7 @@ type_to_s (const gsi::ArgType &a, bool for_return) s += "[]"; break; case gsi::T_map: - s += "map<"; + s += "map<"; if (a.inner_k ()) { s += type_to_s (*a.inner_k (), false); } @@ -203,7 +203,7 @@ type_to_s (const gsi::ArgType &a, bool for_return) if (a.inner ()) { s += type_to_s (*a.inner (), false); } - s += ">"; + s += ">"; break; } if (a.is_cptr () || a.is_ptr ()) { diff --git a/src/pya/pya/pyaCallables.cc b/src/pya/pya/pyaCallables.cc index d35f8bff9..3ab826f9c 100644 --- a/src/pya/pya/pyaCallables.cc +++ b/src/pya/pya/pyaCallables.cc @@ -708,7 +708,7 @@ push_args (gsi::SerialArgs &arglist, const gsi::MethodBase *meth, PyObject *args tl::Variant def_value = a->spec ()->default_value (); gsi::push_arg (arglist, *a, def_value, &heap); } else { - throw tl::Exception (tl::to_string ("No argument provided (positional or keyword) and no default value available")); + throw tl::Exception (tl::to_string (tr ("No argument provided (positional or keyword) and no default value available"))); } } else { if (iarg >= argc) { @@ -809,6 +809,10 @@ method_adaptor (int mid, PyObject *self, PyObject *args, PyObject *kwargs) // handle special methods if (meth->smt () != gsi::MethodBase::None) { + if (kwargs != NULL && PyDict_Size (kwargs) > 0) { + throw tl::Exception (tl::to_string (tr ("Keyword arguments not permitted"))); + } + ret = special_method_impl (meth->smt (), self, args); } else { @@ -936,6 +940,10 @@ method_init_adaptor (int mid, PyObject *self, PyObject *args, PyObject *kwargs) } else { + if (kwargs != NULL && PyDict_Size (kwargs) > 0) { + throw tl::Exception (tl::to_string (tr ("Keyword arguments not permitted"))); + } + // No action required - the object is default-created later once it is really required. if (! PyArg_ParseTuple (args, "")) { return NULL; diff --git a/src/rba/rba/rba.cc b/src/rba/rba/rba.cc index bc40e237c..04e0f37f2 100644 --- a/src/rba/rba/rba.cc +++ b/src/rba/rba/rba.cc @@ -176,9 +176,9 @@ static VALUE get_kwarg (const gsi::ArgType &atype, VALUE kwargs) { if (kwargs != Qnil) { - return rb_hash_lookup2 (kwargs, rb_id2sym (rb_intern (atype.spec ()->name ().c_str ())), Qnil); + return rb_hash_lookup2 (kwargs, rb_id2sym (rb_intern (atype.spec ()->name ().c_str ())), Qundef); } else { - return Qnil; + return Qundef; } } @@ -477,7 +477,7 @@ private: int i = 0; for (gsi::MethodBase::argument_iterator a = (*m)->begin_arguments (); is_valid && a != (*m)->end_arguments (); ++a, ++i) { VALUE arg = i >= argc ? get_kwarg (*a, kwargs) : argv[i]; - if (arg == Qnil) { + if (arg == Qundef) { is_valid = a->spec ()->has_default (); } else if (test_arg (*a, arg, false /*strict*/)) { ++sc; @@ -1060,7 +1060,7 @@ push_args (gsi::SerialArgs &arglist, const gsi::MethodBase *meth, VALUE *argv, i for (gsi::MethodBase::argument_iterator a = meth->begin_arguments (); a != meth->end_arguments (); ++a, ++iarg) { VALUE arg = iarg >= argc ? get_kwarg (*a, kwargs) : argv[iarg]; - if (arg == Qnil) { + if (arg == Qundef) { if (a->spec ()->has_default ()) { if (kwargs_taken == nkwargs) { // leave it to the consumer to establish the default values (that is faster) @@ -1069,7 +1069,7 @@ push_args (gsi::SerialArgs &arglist, const gsi::MethodBase *meth, VALUE *argv, i tl::Variant def_value = a->spec ()->default_value (); gsi::push_arg (arglist, *a, def_value, &heap); } else { - throw tl::Exception (tl::to_string ("No argument provided (positional or keyword) and no default value available")); + throw tl::Exception (tl::to_string (tr ("No argument provided (positional or keyword) and no default value available"))); } } else { if (iarg >= argc) { @@ -1195,10 +1195,18 @@ method_adaptor (int mid, int argc, VALUE *argv, VALUE self, bool ctor) } else if (meth->smt () != gsi::MethodBase::None) { + if (kwargs != Qnil && rb_hash_size_num (kwargs) > 0) { + throw tl::Exception (tl::to_string (tr ("Keyword arguments not permitted"))); + } + ret = special_method_impl (meth, argc, argv, self, ctor); } else if (meth->is_signal ()) { + if (kwargs != Qnil && rb_hash_size_num (kwargs) > 0) { + throw tl::Exception (tl::to_string (tr ("Keyword arguments not permitted on events"))); + } + if (p) { static ID id_set = rb_intern ("set"); @@ -1245,6 +1253,10 @@ method_adaptor (int mid, int argc, VALUE *argv, VALUE self, bool ctor) // calling an iterator method without block -> deliver an enumerator using "to_enum" + if (kwargs != Qnil && rb_hash_size_num (kwargs) > 0) { + throw tl::Exception (tl::to_string (tr ("Keyword arguments not permitted on enumerators"))); + } + static ID id_to_enum = rb_intern ("to_enum"); VALUE method_sym = ID2SYM (rb_intern (meth->primary_name ().c_str ())); diff --git a/testdata/python/kwargs.py b/testdata/python/kwargs.py index 8f30b95d9..23bd87800 100644 --- a/testdata/python/kwargs.py +++ b/testdata/python/kwargs.py @@ -172,6 +172,14 @@ class KWArgsTest(unittest.TestCase): except Exception as ex: self.assertEqual(str(ex), "Value cannot be converted to a floating-point value for argument #2 ('dbu') in CplxTrans.to_s") + try: + t = pya.CplxTrans(1.5, 2.5) + tt = pya.CplxTrans() + tt.assign(other = t) + self.assertEqual(True, False) + except Exception as ex: + self.assertEqual(str(ex), "Keyword arguments not permitted in CplxTrans.assign") + try: t = pya.CplxTrans("17") self.assertEqual(True, False) diff --git a/testdata/ruby/kwargs.rb b/testdata/ruby/kwargs.rb index 9a52cfc06..4299aab9c 100644 --- a/testdata/ruby/kwargs.rb +++ b/testdata/ruby/kwargs.rb @@ -180,6 +180,15 @@ class KWArgs_TestClass < TestBase assert_equal(ex.to_s, "TypeError: no implicit conversion to float from string for argument #2 ('dbu') in CplxTrans::to_s") end + begin + t = RBA::CplxTrans::new(1.5, 2.5) + tt = RBA::CplxTrans::new + tt.assign(other: t) + assert_equal(true, false) + rescue => ex + assert_equal(ex.to_s, "Keyword arguments not permitted in CplxTrans::assign") + end + begin t = RBA::CplxTrans::new("17") assert_equal(true, false) diff --git a/testdata/ruby/tlTest.rb b/testdata/ruby/tlTest.rb index 8980b2ec5..6a6f996d6 100644 --- a/testdata/ruby/tlTest.rb +++ b/testdata/ruby/tlTest.rb @@ -301,10 +301,10 @@ class Tl_TestClass < TestBase assert_equal(my_recipe.name, "rba_test_recipe") assert_equal(my_recipe.description, "description") - g = my_recipe.generator("A" => 6, "B" => 7.0) + g = my_recipe.generator({ "A" => 6, "B" => 7.0 }) assert_equal(g, "rba_test_recipe: A=#6,B=##7") assert_equal("%g" % RBA::Recipe::make(g), "42") - assert_equal("%g" % RBA::Recipe::make(g, "C" => 1.5).to_s, "63") + assert_equal("%g" % RBA::Recipe::make(g, { "C" => 1.5 }).to_s, "63") my_recipe._destroy my_recipe = nil