diff --git a/src/pya/pya/pyaCallables.cc b/src/pya/pya/pyaCallables.cc index 72e4eb7d2..77f3c1728 100644 --- a/src/pya/pya/pyaCallables.cc +++ b/src/pya/pya/pyaCallables.cc @@ -350,9 +350,9 @@ match_method (int mid, PyObject *self, PyObject *args, PyObject *kwargs, bool st PythonPtr arg (i >= argc ? get_kwarg (*a, kwargs) : (is_tuple ? PyTuple_GetItem (args, i) : PyList_GetItem (args, i))); if (! arg) { is_valid = a->spec ()->has_default (); - } else if (test_arg (*a, arg.get (), false /*strict*/)) { + } else if (test_arg (*a, arg.get (), false /*strict*/, false /*object substitution*/)) { ++sc; - } else if (test_arg (*a, arg.get (), true /*loose*/)) { + } else if (test_arg (*a, arg.get (), true /*loose*/, true /*object substitution*/)) { // non-scoring match } else { is_valid = false; @@ -405,7 +405,7 @@ match_method (int mid, PyObject *self, PyObject *args, PyObject *kwargs, bool st int i = 0; for (gsi::MethodBase::argument_iterator a = meth->begin_arguments (); a != meth->end_arguments (); ++a, ++i) { PythonPtr arg (i >= argc ? get_kwarg (*a, kwargs) : (is_tuple ? PyTuple_GetItem (args, i) : PyList_GetItem (args, i))); - if (arg && ! test_arg (*a, arg.get (), true /*loose*/)) { + if (arg && ! test_arg (*a, arg.get (), true /*loose*/, true /*object substitution*/)) { return 0; } } @@ -1116,7 +1116,8 @@ property_setter_impl (int mid, PyObject *self, PyObject *value) // check arguments (count and type) bool is_valid = (*m)->compatible_with_num_args (1); - if (is_valid && ! test_arg (*(*m)->begin_arguments (), value, pass != 0 /*loose in the second pass*/)) { + bool loose = (pass != 0); // loose in the second pass + if (is_valid && ! test_arg (*(*m)->begin_arguments (), value, loose, loose)) { is_valid = false; } diff --git a/src/pya/pya/pyaMarshal.cc b/src/pya/pya/pyaMarshal.cc index 41cc134c0..e6ebed0ed 100644 --- a/src/pya/pya/pyaMarshal.cc +++ b/src/pya/pya/pyaMarshal.cc @@ -1046,7 +1046,7 @@ size_t PythonBasedMapAdaptor::serial_size () const template struct test_arg_func { - void operator() (bool *ret, PyObject *arg, const gsi::ArgType &atype, bool loose) + void operator() (bool *ret, PyObject *arg, const gsi::ArgType &atype, bool loose, bool /*object_substitution*/) { if ((atype.is_cptr () || atype.is_ptr ()) && arg == Py_None) { @@ -1083,7 +1083,7 @@ struct test_arg_func template <> struct test_arg_func { - void operator() (bool *ret, PyObject *, const gsi::ArgType &, bool) + void operator() (bool *ret, PyObject *, const gsi::ArgType &, bool, bool) { // we assume we can convert everything into a variant *ret = true; @@ -1093,7 +1093,7 @@ struct test_arg_func template <> struct test_arg_func { - void operator() (bool *ret, PyObject *arg, const gsi::ArgType &, bool) + void operator() (bool *ret, PyObject *arg, const gsi::ArgType &, bool, bool) { #if PY_MAJOR_VERSION < 3 if (PyString_Check (arg)) { @@ -1117,7 +1117,7 @@ struct test_arg_func template <> struct test_arg_func { - void operator() (bool *ret, PyObject *arg, const gsi::ArgType &atype, bool loose) + void operator() (bool *ret, PyObject *arg, const gsi::ArgType &atype, bool loose, bool /*object_substitution*/) { if ((atype.is_cptr () || atype.is_ptr ()) && arg == Py_None) { // for ptr or cptr, null is an allowed value @@ -1138,7 +1138,7 @@ struct test_arg_func size_t n = PyTuple_Size (arg); for (size_t i = 0; i < n && *ret; ++i) { - if (! test_arg (ainner, PyTuple_GetItem (arg, i), loose)) { + if (! test_arg (ainner, PyTuple_GetItem (arg, i), loose, true /*issue-1651*/)) { *ret = false; } } @@ -1147,7 +1147,7 @@ struct test_arg_func size_t n = PyList_Size (arg); for (size_t i = 0; i < n && *ret; ++i) { - if (! test_arg (ainner, PyList_GetItem (arg, i), loose)) { + if (! test_arg (ainner, PyList_GetItem (arg, i), loose, true /*issue-1651*/)) { *ret = false; } } @@ -1159,7 +1159,7 @@ struct test_arg_func template <> struct test_arg_func { - void operator () (bool *ret, PyObject *arg, const gsi::ArgType &atype, bool loose) + void operator () (bool *ret, PyObject *arg, const gsi::ArgType &atype, bool loose, bool /*object_substitution*/) { if ((atype.is_cptr () || atype.is_ptr ()) && arg == Py_None) { // for ptr or cptr, null is an allowed value @@ -1184,11 +1184,11 @@ struct test_arg_func PyObject *key, *value; Py_ssize_t pos = 0; while (PyDict_Next(arg, &pos, &key, &value)) { - if (! test_arg (ainner_k, key, loose)) { + if (! test_arg (ainner_k, key, loose, true /*issue-1651*/)) { *ret = false; break; } - if (! test_arg (ainner, value, loose)) { + if (! test_arg (ainner, value, loose, true /*issue-1651*/)) { *ret = false; break; } @@ -1199,7 +1199,7 @@ struct test_arg_func template <> struct test_arg_func { - void operator() (bool *ret, PyObject *arg, const gsi::ArgType &atype, bool loose) + void operator() (bool *ret, PyObject *arg, const gsi::ArgType &atype, bool loose, bool object_substitution) { const gsi::ClassBase *acls = atype.cls (); @@ -1209,7 +1209,7 @@ struct test_arg_func return; } - if (loose && (PyTuple_Check (arg) || PyList_Check (arg))) { + if (object_substitution && (PyTuple_Check (arg) || PyList_Check (arg))) { // we may implicitly convert a tuple into a constructor call of a target object - // for now we only check whether the number of arguments is compatible with the list given. @@ -1247,10 +1247,10 @@ struct test_arg_func }; bool -test_arg (const gsi::ArgType &atype, PyObject *arg, bool loose) +test_arg (const gsi::ArgType &atype, PyObject *arg, bool loose, bool object_substitution) { bool ret = false; - gsi::do_on_type () (atype.type (), &ret, arg, atype, loose); + gsi::do_on_type () (atype.type (), &ret, arg, atype, loose, object_substitution); return ret; } diff --git a/src/pya/pya/pyaMarshal.h b/src/pya/pya/pyaMarshal.h index ea61acaef..e0e529382 100644 --- a/src/pya/pya/pyaMarshal.h +++ b/src/pya/pya/pyaMarshal.h @@ -69,7 +69,7 @@ PythonRef pull_arg (const gsi::ArgType &atype, gsi::SerialArgs &aserial, PYAObje * @return True, if the type match */ bool -test_arg (const gsi::ArgType &atype, PyObject *arg, bool loose); +test_arg (const gsi::ArgType &atype, PyObject *arg, bool loose, bool object_substitution); /** * @brief Correct constness if a reference is const and a non-const reference is required diff --git a/src/rba/rba/rba.cc b/src/rba/rba/rba.cc index 8bd642f04..0cef54c62 100644 --- a/src/rba/rba/rba.cc +++ b/src/rba/rba/rba.cc @@ -479,9 +479,9 @@ private: VALUE arg = i >= argc ? get_kwarg (*a, kwargs) : argv[i]; if (arg == Qundef) { is_valid = a->spec ()->has_default (); - } else if (test_arg (*a, arg, false /*strict*/)) { + } else if (test_arg (*a, arg, false /*strict*/, false /*with object substitution*/)) { ++sc; - } else if (test_arg (*a, arg, true /*loose*/)) { + } else if (test_arg (*a, arg, true /*loose*/, true /*with object substitution*/)) { // non-scoring match } else { is_valid = false; diff --git a/src/rba/rba/rbaMarshal.cc b/src/rba/rba/rbaMarshal.cc index 5cacd22e1..7083fd1c7 100644 --- a/src/rba/rba/rbaMarshal.cc +++ b/src/rba/rba/rbaMarshal.cc @@ -1053,7 +1053,7 @@ pull_arg (const gsi::ArgType &atype, Proxy *self, gsi::SerialArgs &aserial, tl:: template struct test_arg_func { - void operator () (bool *ret, VALUE arg, const gsi::ArgType &atype, bool loose) + void operator () (bool *ret, VALUE arg, const gsi::ArgType &atype, bool loose, bool /*object_substitution*/) { if ((atype.is_cptr () || atype.is_ptr ()) && arg == Qnil) { @@ -1101,7 +1101,7 @@ struct test_vector unsigned int len = RARRAY_LEN(arr); VALUE *el = RARRAY_PTR(arr); while (len-- > 0) { - if (! test_arg (ainner, *el++, loose)) { + if (! test_arg (ainner, *el++, loose, true /*issue-1651*/)) { *ret = false; break; } @@ -1112,7 +1112,7 @@ struct test_vector template <> struct test_arg_func { - void operator () (bool *ret, VALUE arg, const gsi::ArgType &atype, bool loose) + void operator () (bool *ret, VALUE arg, const gsi::ArgType &atype, bool loose, bool /*object_substitution*/) { if ((atype.is_cptr () || atype.is_ptr ()) && arg == Qnil) { // for pointers to vectors, nil is a valid value @@ -1141,11 +1141,11 @@ struct HashTestKeyValueData static int hash_test_value_key (VALUE key, VALUE value, VALUE a) { HashTestKeyValueData *args = (HashTestKeyValueData *)a; - if (! test_arg (*args->ainner_k, key, args->loose)) { + if (! test_arg (*args->ainner_k, key, args->loose, true /*issue-1651*/)) { *(args->ret) = false; return ST_STOP; } - if (! test_arg (*args->ainner, value, args->loose)) { + if (! test_arg (*args->ainner, value, args->loose, true /*issue-1651*/)) { *(args->ret) = false; return ST_STOP; } @@ -1155,7 +1155,7 @@ static int hash_test_value_key (VALUE key, VALUE value, VALUE a) template <> struct test_arg_func { - void operator () (bool *ret, VALUE arg, const gsi::ArgType &atype, bool loose) + void operator () (bool *ret, VALUE arg, const gsi::ArgType &atype, bool loose, bool /*object_substitution*/) { if ((atype.is_cptr () || atype.is_ptr ()) && arg == Qnil) { // for pointers to maps, nil is a valid value @@ -1183,14 +1183,14 @@ struct test_arg_func template <> struct test_arg_func { - void operator () (bool *ret, VALUE arg, const gsi::ArgType &atype, bool loose) + void operator () (bool *ret, VALUE arg, const gsi::ArgType &atype, bool loose, bool object_substitution) { if ((atype.is_cptr () || atype.is_ptr ()) && arg == Qnil) { // for const X * or X *, nil is an allowed value *ret = true; - } else if (loose && TYPE (arg) == T_ARRAY) { + } else if (object_substitution && TYPE (arg) == T_ARRAY) { // we may implicitly convert an array into a constructor call of a target object - // for now we only check whether the number of arguments is compatible with the array given. @@ -1234,10 +1234,10 @@ struct test_arg_func }; bool -test_arg (const gsi::ArgType &atype, VALUE arg, bool loose) +test_arg (const gsi::ArgType &atype, VALUE arg, bool loose, bool object_substitution) { bool ret = false; - gsi::do_on_type () (atype.type (), &ret, arg, atype, loose); + gsi::do_on_type () (atype.type (), &ret, arg, atype, loose, object_substitution); return ret; } diff --git a/src/rba/rba/rbaMarshal.h b/src/rba/rba/rbaMarshal.h index 9e8ea4e07..436ef01cd 100644 --- a/src/rba/rba/rbaMarshal.h +++ b/src/rba/rba/rbaMarshal.h @@ -62,7 +62,7 @@ void push_arg (const gsi::ArgType &atype, gsi::SerialArgs &aserial, VALUE arg, t * otherwise: * argument must be of the requested type */ -bool test_arg (const gsi::ArgType &atype, VALUE arg, bool loose); +bool test_arg (const gsi::ArgType &atype, VALUE arg, bool loose, bool object_substitution); } diff --git a/testdata/python/dbPolygonTest.py b/testdata/python/dbPolygonTest.py index ec1c4a3b6..fb5349d45 100644 --- a/testdata/python/dbPolygonTest.py +++ b/testdata/python/dbPolygonTest.py @@ -746,6 +746,16 @@ class DBPolygonTests(unittest.TestCase): poly = pya.Polygon(hull).insert_hole(hole1).insert_hole(hole2) self.assertEqual(str(poly), "(0,0;0,3000;6000,3000;6000,0/1000,1000;2000,1000;2000,2000;1000,2000/3000,1000;4000,1000;4000,2000;3000,2000)") + def test_argumentShortcuts(self): + + # implicit conversion to a Point array: + poly = pya.Polygon([ (0,0), (0,1000), (1000,1000) ]) + self.assertEqual(str(poly), "(0,0;0,1000;1000,1000)") + + # issue 1651 - no binding to Box constructor + poly = pya.Polygon([ (0,0), (0,1000), (1000,1000), (1000,0) ]) + self.assertEqual(str(poly), "(0,0;0,1000;1000,1000;1000,0)") + # run unit tests if __name__ == '__main__': suite = unittest.TestLoader().loadTestsFromTestCase(DBPolygonTests) diff --git a/testdata/ruby/dbPolygonTest.rb b/testdata/ruby/dbPolygonTest.rb index cb1910017..ef598737a 100644 --- a/testdata/ruby/dbPolygonTest.rb +++ b/testdata/ruby/dbPolygonTest.rb @@ -882,6 +882,18 @@ class DBPolygon_TestClass < TestBase end + def test_argumentShortcuts + + # implicit conversion to a Point array: + poly = RBA::Polygon.new([ [0,0], [0,1000], [1000,1000] ]) + assert_equal(poly.to_s, "(0,0;0,1000;1000,1000)") + + # issue 1651 - no binding to Box constructor + poly = RBA::Polygon.new([ [0,0], [0,1000], [1000,1000], [1000,0] ]) + assert_equal(poly.to_s, "(0,0;0,1000;1000,1000;1000,0)") + + end + end load("test_epilogue.rb")