// Copyright (c) 2021 PaddlePaddle Authors. All Rights Reserved. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. #include "paddle/fluid/pybind/op_function_common.h" #include #include #include #include #include #include #include #include "paddle/fluid/framework/attribute.h" #include "paddle/fluid/framework/op_info.h" #include "paddle/fluid/framework/op_registry.h" #include "paddle/fluid/framework/variable.h" #include "paddle/fluid/imperative/tracer.h" #include "paddle/fluid/imperative/type_defs.h" #include "paddle/fluid/operators/ops_extra_info.h" #include "paddle/fluid/pybind/eager.h" #include "paddle/fluid/pybind/eager_utils.h" #include "paddle/fluid/pybind/imperative.h" #include "paddle/phi/common/complex.h" #include "paddle/pir/include/core/block.h" #include "paddle/pir/include/core/op_result.h" #include "paddle/pir/include/core/value.h" namespace paddle::pybind { class OpAttrTypeMap { public: static OpAttrTypeMap& Instance() { static OpAttrTypeMap g_op_attr_type_map; return g_op_attr_type_map; } std::unordered_map< std::string, std::unordered_map>& Map() { return ops_attrtype_map_; } private: OpAttrTypeMap() : ops_attrtype_map_() {} std::unordered_map< std::string, std::unordered_map> ops_attrtype_map_; }; extern PyTypeObject* g_vartype_pytype; extern PyTypeObject* g_data_type_pytype; extern PyTypeObject* g_blockdesc_pytype; extern PyTypeObject* p_tensor_type; bool PyObject_CheckBool(PyObject** obj) { return PyBool_Check(*obj); } bool PyObject_CheckVarType(PyObject* obj) { return PyObject_TypeCheck(obj, g_vartype_pytype); } bool PyObject_CheckDataType(PyObject* obj) { return PyObject_TypeCheck(obj, g_data_type_pytype); } bool PyObject_CheckTensor(PyObject* obj) { return PyObject_TypeCheck(obj, p_tensor_type); } bool PyObject_CheckLong(PyObject* obj) { if ((PyLong_Check(obj) && !PyBool_Check(obj)) || // NOLINT PyObject_CheckVarType(obj) || // NOLINT PyObject_CheckDataType(obj) || // NOLINT (PyObject_CheckTensor(obj) && reinterpret_cast(obj)->tensor.numel() == 1)) { return true; } std::string type_name = std::string(reinterpret_cast(obj->ob_type)->tp_name); if (type_name.find("numpy.int") != std::string::npos) { return true; } return false; } int32_t PyObject_ToInt32(PyObject* obj) { int64_t res = 0; if ((PyLong_Check(obj) && !PyBool_Check(obj)) || // NOLINT PyObject_CheckVarType(obj) || // NOLINT PyObject_CheckDataType(obj) || // NOLINT (PyObject_CheckTensor(obj) && reinterpret_cast(obj)->tensor.numel() == 1)) { res = PyLong_AsLongLong(obj); } else { std::string type_name = std::string(reinterpret_cast(obj->ob_type)->tp_name); if (type_name.find("numpy.int") != std::string::npos) { auto num_obj = PyNumber_Long(obj); res = PyLong_AsLongLong(num_obj); Py_DECREF(num_obj); } else { PADDLE_THROW( common::errors::InvalidType("Cannot convert %s to int32", type_name)); } } if (res > std::numeric_limits::max() || res < std::numeric_limits::min()) { PADDLE_THROW(common::errors::OutOfRange( "Integer value %ld exceeds int32 range [%d, %d]", res, std::numeric_limits::min(), std::numeric_limits::max())); } return static_cast(res); } uint32_t PyObject_ToUInt32(PyObject* obj) { uint32_t res = 0; if ((PyLong_Check(obj) && !PyBool_Check(obj)) || // NOLINT PyObject_CheckVarType(obj) || // NOLINT PyObject_CheckDataType(obj) || // NOLINT (PyObject_CheckTensor(obj) && reinterpret_cast(obj)->tensor.numel() == 1)) { res = static_cast(PyLong_AsUnsignedLong(obj)); return res; } std::string type_name = std::string(reinterpret_cast(obj->ob_type)->tp_name); if (type_name.find("numpy.int") != std::string::npos) { auto num_obj = PyNumber_Long(obj); res = static_cast(PyLong_AsUnsignedLong(obj)); Py_DECREF(num_obj); } else { PADDLE_THROW( common::errors::InvalidType("Cannot convert %s to long", type_name)); } return res; } int64_t PyObject_ToInt64(PyObject* obj) { int64_t res = 0; if ((PyLong_Check(obj) && !PyBool_Check(obj)) || // NOLINT PyObject_CheckVarType(obj) || // NOLINT PyObject_CheckDataType(obj) || // NOLINT (PyObject_CheckTensor(obj) && reinterpret_cast(obj)->tensor.numel() == 1)) { res = PyLong_AsLongLong(obj); return res; } std::string type_name = std::string(reinterpret_cast(obj->ob_type)->tp_name); if (type_name.find("numpy.int") != std::string::npos) { auto num_obj = PyNumber_Long(obj); res = PyLong_AsLongLong(num_obj); Py_DECREF(num_obj); } else { PADDLE_THROW(common::errors::InvalidType("Cannot convert %s to long long", type_name)); } return res; } uint64_t PyObject_ToUInt64(PyObject* obj) { uint64_t res = 0; if ((PyLong_Check(obj) && !PyBool_Check(obj)) || // NOLINT PyObject_CheckVarType(obj) || // NOLINT PyObject_CheckDataType(obj) || // NOLINT (PyObject_CheckTensor(obj) && reinterpret_cast(obj)->tensor.numel() == 1)) { res = PyLong_AsUnsignedLongLong(obj); return res; } std::string type_name = std::string(reinterpret_cast(obj->ob_type)->tp_name); if (type_name.find("numpy.int") != std::string::npos) { auto num_obj = PyNumber_Long(obj); res = PyLong_AsUnsignedLongLong(obj); Py_DECREF(num_obj); } else { PADDLE_THROW( common::errors::InvalidType("Cannot convert %s to long", type_name)); } return res; } size_t PyObject_ToSize_t(PyObject* obj) { size_t res = 0; if ((PyLong_Check(obj) && !PyBool_Check(obj)) || // NOLINT PyObject_CheckVarType(obj) || // NOLINT PyObject_CheckDataType(obj) || // NOLINT (PyObject_CheckTensor(obj) && reinterpret_cast(obj)->tensor.numel() == 1)) { res = PyLong_AsSize_t(obj); return res; } std::string type_name = std::string(reinterpret_cast(obj->ob_type)->tp_name); if (type_name.find("numpy.int") != std::string::npos) { auto num_obj = PyNumber_Long(obj); res = PyLong_AsSize_t(num_obj); Py_DECREF(num_obj); } else { PADDLE_THROW(common::errors::InvalidType("Cannot convert %s to long long", type_name)); } return res; } bool PyObject_CheckFloat(PyObject* obj) { if (PyFloat_Check(obj) || PyLong_Check(obj) || (PyObject_CheckTensor(obj) && reinterpret_cast(obj)->tensor.numel() == 1)) { return true; } auto type_name = std::string(reinterpret_cast(obj->ob_type)->tp_name); VLOG(4) << "type_name: " << type_name; if (type_name.find("numpy") != std::string::npos && type_name.find("numpy.complex") == std::string::npos) { return true; } return false; } double PyObject_ToDouble(PyObject* obj) { double res = 0.0; if (PyFloat_Check(obj) || PyLong_Check(obj) || (PyObject_CheckTensor(obj) && reinterpret_cast(obj)->tensor.numel() == 1)) { res = PyFloat_AsDouble(obj); return res; } auto type_name = std::string(reinterpret_cast(obj->ob_type)->tp_name); if (type_name.find("numpy") != std::string::npos && type_name.find("numpy.complex") == std::string::npos) { auto num_obj = PyNumber_Float(obj); res = PyFloat_AsDouble(num_obj); Py_DECREF(num_obj); } else { PADDLE_THROW( common::errors::InvalidType("Cannot convert %s to double", type_name)); } return res; } bool PyObject_CheckComplexOrToComplex(PyObject** obj) { if (PyComplex_Check(*obj) || PyObject_TypeCheck(*obj, g_vartype_pytype) || // NOLINT PyObject_TypeCheck(*obj, p_tensor_type)) { // NOLINT return true; } if (std::string(((PyTypeObject*)(*obj)->ob_type)->tp_name) // NOLINT .find("numpy.complex") != std::string::npos) { return true; } // consider numpy cfloat & numpy cdouble? return false; } bool PyObject_CheckString(PyObject* obj) { return PyUnicode_Check(obj); } bool CastPyArg2Boolean(PyObject* obj, const std::string& op_type, ssize_t arg_pos) { if (obj == Py_None || obj == Py_False) { return false; // To be compatible with QA integration testing. Some // test case pass in None. } else if (obj == Py_True) { return true; } else { PADDLE_THROW(common::errors::InvalidType( "%s(): argument (position %d) must be " "bool, but got %s", op_type, arg_pos + 1, ((PyTypeObject*)obj->ob_type)->tp_name)); // NOLINT } return false; } bool CastPyArg2Boolean(PyObject* obj, const std::string& op_type, ssize_t arg_pos, bool default_value) { if (obj) { return CastPyArg2Boolean(obj, op_type, arg_pos); } else { return default_value; } } void CastPyArg2AttrBoolean(PyObject* obj, paddle::framework::AttributeMap& attrs, // NOLINT const std::string& key, const std::string& op_type, ssize_t arg_pos) { attrs[key] = CastPyArg2Boolean(obj, op_type, arg_pos); } int CastPyArg2Int(PyObject* obj, const std::string& op_type, ssize_t arg_pos) { if (PyObject_CheckLong(obj)) { return PyObject_ToInt32(obj); } else { PADDLE_THROW(common::errors::InvalidType( "%s(): argument (position %d) must be " "int, but got %s", op_type, arg_pos + 1, ((PyTypeObject*)obj->ob_type)->tp_name)); // NOLINT } return 0; } int CastPyArg2Int(PyObject* obj, const std::string& op_type, ssize_t arg_pos, int default_value) { if (obj != nullptr) { return CastPyArg2Int(obj, op_type, arg_pos); } else { return default_value; } } void CastPyArg2AttrInt(PyObject* obj, paddle::framework::AttributeMap& attrs, // NOLINT const std::string& key, const std::string& op_type, ssize_t arg_pos) { attrs[key] = CastPyArg2Int(obj, op_type, arg_pos); } int64_t CastPyArg2Long(PyObject* obj, const std::string& op_type, ssize_t arg_pos) { if (PyObject_CheckLong(obj)) { return PyObject_ToInt64(obj); } else { PADDLE_THROW(common::errors::InvalidType( "%s(): argument (position %d) must be " "long, but got %s", op_type, arg_pos + 1, ((PyTypeObject*)obj->ob_type)->tp_name)); // NOLINT } return 0; } int64_t CastPyArg2Long(PyObject* obj, const std::string& op_type, ssize_t arg_pos, int64_t default_value) { if (obj != nullptr) { return CastPyArg2Long(obj, op_type, arg_pos); } else { return default_value; } } void CastPyArg2AttrLong(PyObject* obj, paddle::framework::AttributeMap& attrs, // NOLINT const std::string& key, const std::string& op_type, ssize_t arg_pos) { attrs[key] = CastPyArg2Long(obj, op_type, arg_pos); } void CastPyArg2AttrScalar(PyObject* obj, paddle::framework::AttributeMap& attrs, // NOLINT const std::string& key, const std::string& op_type, ssize_t arg_pos) { attrs[key] = CastPyArg2Scalar(obj, op_type, arg_pos); } float16 CastPyArg2Float16(PyObject* obj, const std::string& op_type, ssize_t arg_pos) { return static_cast(CastPyArg2Double(obj, op_type, arg_pos)); } float CastPyArg2Float(PyObject* obj, const std::string& op_type, ssize_t arg_pos) { return static_cast(CastPyArg2Double(obj, op_type, arg_pos)); } float CastPyArg2Float(PyObject* obj, const std::string& op_type, ssize_t arg_pos, float default_value) { if (obj != nullptr) { return CastPyArg2Float(obj, op_type, arg_pos); } else { return default_value; } } void CastPyArg2AttrFloat(PyObject* obj, paddle::framework::AttributeMap& attrs, // NOLINT const std::string& key, const std::string& op_type, ssize_t arg_pos) { attrs[key] = CastPyArg2Float(obj, op_type, arg_pos); } double CastPyArg2Double(PyObject* obj, const std::string& op_type, ssize_t arg_pos) { if (PyObject_CheckFloat(obj)) { return PyObject_ToDouble(obj); // NOLINT } else { PADDLE_THROW(common::errors::InvalidType( "%s(): argument (position %d) must be " "double, but got %s", op_type, arg_pos + 1, ((PyTypeObject*)obj->ob_type)->tp_name)); // NOLINT } return 0.0; } double CastPyArg2Double(PyObject* obj, const std::string& op_type, ssize_t arg_pos, double default_value) { if (obj != nullptr) { return CastPyArg2Double(obj, op_type, arg_pos); } else { return default_value; } } phi::dtype::complex CastPyArg2Complex(PyObject* obj, const std::string& op_type, ssize_t arg_pos) { PyTypeObject* type = obj->ob_type; auto type_name = std::string(type->tp_name); if (PyComplex_Check(obj)) { double real = PyComplex_RealAsDouble(obj); double imag = PyComplex_ImagAsDouble(obj); return phi::dtype::complex(real, imag); // NOLINT } else if (type_name == "numpy.complex64") { Py_complex v = PyComplex_AsCComplex(obj); return phi::dtype::complex(v.real, v.imag); } else { PADDLE_THROW(common::errors::InvalidType( "%s(): argument (position %d) must be " "complex, but got %s", op_type, arg_pos + 1, ((PyTypeObject*)obj->ob_type)->tp_name)); // NOLINT } return phi::dtype::complex(0, 0); } phi::dtype::complex CastPyArg2Complex128(PyObject* obj, const std::string& op_type, ssize_t arg_pos) { if (PyComplex_Check(obj)) { double real = PyComplex_RealAsDouble(obj); double imag = PyComplex_ImagAsDouble(obj); return phi::dtype::complex(real, imag); } else { PADDLE_THROW(common::errors::InvalidType( "%s(): argument (position %d) must be " "complex, but got %s", op_type, arg_pos + 1, ((PyTypeObject*)obj->ob_type)->tp_name)); // NOLINT } return phi::dtype::complex(0, 0); } void CastPyArg2AttrDouble(PyObject* obj, paddle::framework::AttributeMap& attrs, // NOLINT const std::string& key, const std::string& op_type, ssize_t arg_pos) { attrs[key] = CastPyArg2Double(obj, op_type, arg_pos); } std::string CastPyArg2String(PyObject* obj, const std::string& op_type, ssize_t arg_pos) { if (PyObject_CheckString(obj)) { Py_ssize_t size = 0; const char* data = nullptr; data = PyUnicode_AsUTF8AndSize(obj, &size); return std::string(data, (size_t)size); // NOLINT } else { PADDLE_THROW(common::errors::InvalidType( "%s(): argument (position %d) must be " "str, but got %s", op_type, arg_pos + 1, ((PyTypeObject*)obj->ob_type)->tp_name)); // NOLINT } return ""; } std::string CastPyArg2String(PyObject* obj, const std::string& op_type, ssize_t arg_pos, std::string default_value) { if (obj != nullptr) { return CastPyArg2String(obj, op_type, arg_pos); } else { return default_value; } } void CastPyArg2AttrString(PyObject* obj, paddle::framework::AttributeMap& attrs, // NOLINT const std::string& key, const std::string& op_type, ssize_t arg_pos) { attrs[key] = CastPyArg2String(obj, op_type, arg_pos); } std::vector CastPyArg2Booleans(PyObject* obj, const std::string& op_type, ssize_t arg_pos) { std::vector value; if (PyList_Check(obj)) { Py_ssize_t len = PyList_Size(obj); PyObject* item = nullptr; for (Py_ssize_t i = 0; i < len; i++) { item = PyList_GetItem(obj, i); if (PyObject_CheckBool(&item)) { value.emplace_back(PyLong_AsLong(item)); } else { PADDLE_THROW(common::errors::InvalidType( "%s(): argument (position %d) must be " "list of bool, but got %s at pos %d", op_type, arg_pos + 1, ((PyTypeObject*)item->ob_type)->tp_name, // NOLINT i)); } } } else if (PyTuple_Check(obj)) { Py_ssize_t len = PyTuple_Size(obj); PyObject* item = nullptr; for (Py_ssize_t i = 0; i < len; i++) { item = PyTuple_GetItem(obj, i); if (PyObject_CheckBool(&item)) { value.emplace_back(PyLong_AsLong(item)); } else { PADDLE_THROW(common::errors::InvalidType( "%s(): argument (position %d) must be " "list of bool, but got %s at pos %d", op_type, arg_pos + 1, ((PyTypeObject*)item->ob_type)->tp_name, // NOLINT i)); } } } else { PADDLE_THROW(common::errors::InvalidType( "%s(): argument (position %d) must be " "list or tuple, but got %s", op_type, arg_pos + 1, ((PyTypeObject*)obj->ob_type)->tp_name)); // NOLINT } return value; } std::vector CastPyArg2Booleans(PyObject* obj, const std::string& op_type, ssize_t arg_pos, std::vector default_value) { if (obj != nullptr) { return CastPyArg2Booleans(obj, op_type, arg_pos); } else { return default_value; } } void CastPyArg2AttrBooleans(PyObject* obj, paddle::framework::AttributeMap& attrs, // NOLINT const std::string& key, const std::string& op_type, ssize_t arg_pos) { attrs[key] = CastPyArg2Booleans(obj, op_type, arg_pos); } std::vector CastPyArg2Ints(PyObject* obj, const std::string& op_type, ssize_t arg_pos) { std::vector value; if (PyList_Check(obj)) { Py_ssize_t len = PyList_Size(obj); value.reserve(len); PyObject* item = nullptr; for (Py_ssize_t i = 0; i < len; i++) { item = PyList_GetItem(obj, i); if (PyObject_CheckLong(item)) { value.emplace_back(PyObject_ToInt32(item)); } else { PADDLE_THROW(common::errors::InvalidType( "%s(): argument (position %d) must be " "list of int, but got %s at pos %d", op_type, arg_pos + 1, ((PyTypeObject*)item->ob_type)->tp_name, // NOLINT i)); } } } else if (PyTuple_Check(obj)) { Py_ssize_t len = PyTuple_Size(obj); value.reserve(len); PyObject* item = nullptr; for (Py_ssize_t i = 0; i < len; i++) { item = PyTuple_GetItem(obj, i); if (PyObject_CheckLong(item)) { value.emplace_back(PyObject_ToInt32(item)); } else { PADDLE_THROW(common::errors::InvalidType( "%s(): argument (position %d) must be " "list of int, but got %s at pos %d", op_type, arg_pos + 1, ((PyTypeObject*)item->ob_type)->tp_name, // NOLINT i)); } } } else if (PySequence_Check(obj) && !PyObject_TypeCheck(obj, p_tensor_type)) { Py_ssize_t len = PySequence_Size(obj); value.reserve(len); PyObject* item = nullptr; for (Py_ssize_t i = 0; i < len; i++) { item = PySequence_GetItem(obj, i); if (PyObject_CheckLong(item)) { value.emplace_back(PyObject_ToInt32(item)); } else { PADDLE_THROW(common::errors::InvalidType( "%s(): argument (position %d) must be " "list of int, but got %s at pos %d", op_type, arg_pos + 1, ((PyTypeObject*)item->ob_type)->tp_name, // NOLINT i)); } Py_DECREF(item); } } else if (PyObject_CheckLong(obj)) { value.emplace_back(PyObject_ToInt32(obj)); } else { PADDLE_THROW(common::errors::InvalidType( "%s(): argument (position %d) must be " "list or tuple, but got %s", op_type, arg_pos + 1, ((PyTypeObject*)obj->ob_type)->tp_name)); // NOLINT } return value; } std::vector CastPyArg2Ints(PyObject* obj, const std::string& op_type, ssize_t arg_pos, std::vector default_value) { if (obj != nullptr && obj != Py_None) { return CastPyArg2Ints(obj, op_type, arg_pos); } else { return default_value; } } void CastPyArg2AttrInts(PyObject* obj, paddle::framework::AttributeMap& attrs, // NOLINT const std::string& key, const std::string& op_type, ssize_t arg_pos) { attrs[key] = CastPyArg2Ints(obj, op_type, arg_pos); } std::vector CastPyArg2Longs(PyObject* obj, const std::string& op_type, ssize_t arg_pos) { std::vector value; if (PyList_Check(obj)) { Py_ssize_t len = PyList_Size(obj); PyObject* item = nullptr; for (Py_ssize_t i = 0; i < len; i++) { item = PyList_GetItem(obj, i); if (PyObject_CheckLong(item)) { value.emplace_back(PyObject_ToInt64(item)); } else { PADDLE_THROW(common::errors::InvalidType( "%s(): argument (position %d) must be " "list of int, but got %s at pos %d", op_type, arg_pos + 1, ((PyTypeObject*)item->ob_type)->tp_name, // NOLINT i)); } } } else if (PyTuple_Check(obj)) { Py_ssize_t len = PyTuple_Size(obj); PyObject* item = nullptr; for (Py_ssize_t i = 0; i < len; i++) { item = PyTuple_GetItem(obj, i); if (PyObject_CheckLong(item)) { value.emplace_back(PyObject_ToInt64(item)); } else { PADDLE_THROW(common::errors::InvalidType( "%s(): argument (position %d) must be " "list of int, but got %s at pos %d", op_type, arg_pos + 1, ((PyTypeObject*)item->ob_type)->tp_name, // NOLINT i)); } } } else if (PySequence_Check(obj) && !PyObject_TypeCheck(obj, p_tensor_type)) { Py_ssize_t len = PySequence_Size(obj); PyObject* item = nullptr; for (Py_ssize_t i = 0; i < len; i++) { item = PySequence_GetItem(obj, i); if (PyObject_CheckLong(item)) { value.emplace_back(PyObject_ToInt64(item)); } else { PADDLE_THROW(common::errors::InvalidType( "%s(): argument (position %d) must be " "list of int, but got %s at pos %d", op_type, arg_pos + 1, ((PyTypeObject*)item->ob_type)->tp_name, // NOLINT i)); } Py_DECREF(item); } } else if (obj == Py_None) { return {}; } else if (PyObject_CheckLong(obj)) { return {PyObject_ToInt64(obj)}; // NOLINT } else { PADDLE_THROW(common::errors::InvalidType( "%s(): argument (position %d) must be " "list or tuple, but got %s", op_type, arg_pos + 1, ((PyTypeObject*)obj->ob_type)->tp_name)); // NOLINT } return value; } std::vector CastPyArg2Longs(PyObject* obj, const std::string& op_type, ssize_t arg_pos, std::vector default_value) { if (obj) { return CastPyArg2Longs(obj, op_type, arg_pos); } else { return default_value; } } void CastPyArg2AttrLongs(PyObject* obj, paddle::framework::AttributeMap& attrs, // NOLINT const std::string& key, const std::string& op_type, ssize_t arg_pos) { attrs[key] = CastPyArg2Longs(obj, op_type, arg_pos); } std::vector CastPyArg2Floats(PyObject* obj, const std::string& op_type, ssize_t arg_pos) { std::vector value; if (PyList_Check(obj)) { Py_ssize_t len = PyList_Size(obj); PyObject* item = nullptr; for (Py_ssize_t i = 0; i < len; i++) { item = PyList_GetItem(obj, i); if (PyObject_CheckFloat(item)) { value.emplace_back(PyObject_ToDouble(item)); } else { PADDLE_THROW(common::errors::InvalidType( "%s(): argument (position %d) must be " "list of float, but got %s at pos %d", op_type, arg_pos + 1, ((PyTypeObject*)item->ob_type)->tp_name, // NOLINT i)); } } } else if (PyTuple_Check(obj)) { Py_ssize_t len = PyTuple_Size(obj); PyObject* item = nullptr; for (Py_ssize_t i = 0; i < len; i++) { item = PyTuple_GetItem(obj, i); if (PyObject_CheckFloat(item)) { value.emplace_back(PyObject_ToDouble(item)); } else { PADDLE_THROW(common::errors::InvalidType( "%s(): argument (position %d) must be " "list of float, but got %s at pos %d", op_type, arg_pos + 1, ((PyTypeObject*)item->ob_type)->tp_name, // NOLINT i)); } } } else if (PySequence_Check(obj) && !PyObject_TypeCheck(obj, p_tensor_type)) { Py_ssize_t len = PySequence_Size(obj); PyObject* item = nullptr; for (Py_ssize_t i = 0; i < len; i++) { item = PySequence_GetItem(obj, i); if (PyObject_CheckFloat(item)) { value.emplace_back(PyObject_ToDouble(item)); } else { PADDLE_THROW(common::errors::InvalidType( "%s(): argument (position %d) must be " "list of float, but got %s at pos %d", op_type, arg_pos + 1, ((PyTypeObject*)item->ob_type)->tp_name, // NOLINT i)); } Py_DECREF(item); } } else { PADDLE_THROW(common::errors::InvalidType( "%s(): argument (position %d) must be " "list or tuple, but got %s", op_type, arg_pos + 1, ((PyTypeObject*)obj->ob_type)->tp_name)); // NOLINT } return value; } std::vector CastPyArg2Floats(PyObject* obj, const std::string& op_type, ssize_t arg_pos, std::vector default_value) { if (obj != nullptr) { return CastPyArg2Floats(obj, op_type, arg_pos); } else { return default_value; } } void CastPyArg2AttrFloats(PyObject* obj, paddle::framework::AttributeMap& attrs, // NOLINT const std::string& key, const std::string& op_type, ssize_t arg_pos) { attrs[key] = CastPyArg2Floats(obj, op_type, arg_pos); } std::vector CastPyArg2Float64s(PyObject* obj, const std::string& op_type, ssize_t arg_pos) { std::vector value; if (PyList_Check(obj)) { Py_ssize_t len = PyList_Size(obj); PyObject* item = nullptr; for (Py_ssize_t i = 0; i < len; i++) { item = PyList_GetItem(obj, i); if (PyObject_CheckFloat(item)) { value.emplace_back(PyObject_ToDouble(item)); } else { PADDLE_THROW(common::errors::InvalidType( "%s(): argument (position %d) must be " "list of float, but got %s at pos %d", op_type, arg_pos + 1, ((PyTypeObject*)item->ob_type)->tp_name, // NOLINT i)); } } } else if (PyTuple_Check(obj)) { Py_ssize_t len = PyTuple_Size(obj); PyObject* item = nullptr; for (Py_ssize_t i = 0; i < len; i++) { item = PyTuple_GetItem(obj, i); if (PyObject_CheckFloat(item)) { value.emplace_back(PyObject_ToDouble(item)); } else { PADDLE_THROW(common::errors::InvalidType( "%s(): argument (position %d) must be " "list of float, but got %s at pos %d", op_type, arg_pos + 1, ((PyTypeObject*)item->ob_type)->tp_name, // NOLINT i)); } } } else if (PySequence_Check(obj) && !PyObject_TypeCheck(obj, p_tensor_type)) { Py_ssize_t len = PySequence_Size(obj); PyObject* item = nullptr; for (Py_ssize_t i = 0; i < len; i++) { item = PySequence_GetItem(obj, i); if (PyObject_CheckFloat(item)) { value.emplace_back(PyObject_ToDouble(item)); } else { PADDLE_THROW(common::errors::InvalidType( "%s(): argument (position %d) must be " "list of float, but got %s at pos %d", op_type, arg_pos + 1, ((PyTypeObject*)item->ob_type)->tp_name, // NOLINT i)); } Py_DECREF(item); } } else { PADDLE_THROW(common::errors::InvalidType( "%s(): argument (position %d) must be " "list or tuple, but got %s", op_type, arg_pos + 1, ((PyTypeObject*)obj->ob_type)->tp_name)); // NOLINT } return value; } std::vector CastPyArg2Float64s(PyObject* obj, const std::string& op_type, ssize_t arg_pos, std::vector default_value) { if (obj != nullptr) { return CastPyArg2Float64s(obj, op_type, arg_pos); } else { return default_value; } } void CastPyArg2AttrFloat64s(PyObject* obj, paddle::framework::AttributeMap& attrs, // NOLINT const std::string& key, const std::string& op_type, ssize_t arg_pos) { attrs[key] = CastPyArg2Float64s(obj, op_type, arg_pos); } void CastPyArg2AttrScalars(PyObject* obj, paddle::framework::AttributeMap& attrs, // NOLINT const std::string& key, const std::string& op_type, ssize_t arg_pos) { attrs[key] = CastPyArg2Scalars(obj, op_type, arg_pos); } std::vector CastPyArg2Strings(PyObject* obj, const std::string& op_type, ssize_t arg_pos) { std::vector views; if (PyList_Check(obj)) { Py_ssize_t len = PyList_Size(obj); views.reserve(len); PyObject* item = nullptr; for (Py_ssize_t i = 0; i < len; i++) { item = PyList_GetItem(obj, i); if (PyObject_CheckString(item)) { Py_ssize_t size = 0; const char* data = nullptr; data = PyUnicode_AsUTF8AndSize(item, &size); views.emplace_back(std::string_view(data, (size_t)size)); // NOLINT } else { PADDLE_THROW(common::errors::InvalidType( "%s(): argument (position %d) must be " "list of str, but got %s at pos %d", op_type, arg_pos + 1, ((PyTypeObject*)item->ob_type)->tp_name, // NOLINT i)); } } } else if (PyTuple_Check(obj)) { Py_ssize_t len = PyTuple_Size(obj); views.reserve(len); PyObject* item = nullptr; for (Py_ssize_t i = 0; i < len; i++) { item = PyTuple_GetItem(obj, i); if (PyObject_CheckString(item)) { Py_ssize_t size = 0; const char* data = nullptr; data = PyUnicode_AsUTF8AndSize(item, &size); views.emplace_back(std::string_view(data, (size_t)size)); // NOLINT } else { PADDLE_THROW(common::errors::InvalidType( "%s(): argument (position %d) must be " "list of str, but got %s at pos %d", op_type, arg_pos + 1, ((PyTypeObject*)item->ob_type)->tp_name, // NOLINT i)); } } } else { PADDLE_THROW(common::errors::InvalidType( "%s(): argument (position %d) must be " "list or tuple, but got %s", op_type, arg_pos + 1, ((PyTypeObject*)obj->ob_type)->tp_name)); // NOLINT } std::vector value; value.reserve(views.size()); for (const auto& view : views) { value.emplace_back(view); } return value; } std::vector CastPyArg2Strings( PyObject* obj, const std::string& op_type, ssize_t arg_pos, std::vector default_value) { if (obj != nullptr) { return CastPyArg2Strings(obj, op_type, arg_pos); } else { return default_value; } } void CastPyArg2AttrStrings(PyObject* obj, paddle::framework::AttributeMap& attrs, // NOLINT const std::string& key, const std::string& op_type, ssize_t arg_pos) { attrs[key] = CastPyArg2Strings(obj, op_type, arg_pos); } std::vector CastPyArg2Scalars( PyObject* obj, const std::string& op_type, ssize_t arg_pos) { if (obj == Py_None) { PADDLE_THROW(common::errors::InvalidType( "%s(): argument (position %d) must be " "a list of int, float, or bool, but got %s", op_type, arg_pos + 1, ((PyTypeObject*)obj->ob_type)->tp_name)); // NOLINT } PyTypeObject* type = obj->ob_type; auto type_name = std::string(type->tp_name); VLOG(4) << "type_name: " << type_name; if (PyList_Check(obj)) { Py_ssize_t len = PyList_Size(obj); PyObject* item = nullptr; item = PyList_GetItem(obj, 0); if (PyObject_CheckFloat(item)) { std::vector value; for (Py_ssize_t i = 0; i < len; i++) { item = PyList_GetItem(obj, i); value.emplace_back( paddle::experimental::Scalar{PyObject_ToDouble(item)}); } return value; } else if (PyObject_CheckLong(item)) { std::vector value; for (Py_ssize_t i = 0; i < len; i++) { item = PyList_GetItem(obj, i); value.emplace_back( paddle::experimental::Scalar{PyObject_ToInt64(item)}); } return value; } else if (PyObject_CheckComplexOrToComplex(&item)) { std::vector value; for (Py_ssize_t i = 0; i < len; i++) { item = PyList_GetItem(obj, i); Py_complex v = PyComplex_AsCComplex(item); value.emplace_back( paddle::experimental::Scalar{std::complex(v.real, v.imag)}); } return value; } } else { PADDLE_THROW(common::errors::InvalidType( "%s(): argument (position %d) must be " "a list of int, float, complex, or bool, but got %s", op_type, arg_pos + 1, ((PyTypeObject*)obj->ob_type)->tp_name)); // NOLINT } // Fake a ScalarArray return std::vector( {paddle::experimental::Scalar(1.0)}); } void CastPyArg2AttrBlock(PyObject* obj, paddle::framework::AttributeMap& attrs, // NOLINT const std::string& key, const std::string& op_type, ssize_t arg_pos) { ::pybind11::detail::instance* inst = (::pybind11::detail::instance*)obj; // NOLINT if (!PyObject_TypeCheck((PyObject*)inst, g_blockdesc_pytype)) { // NOLINT PADDLE_THROW(common::errors::InvalidType( "%s(): argument (position %d) must be " "BlockDesc, but got %s", op_type, arg_pos + 1, ((PyTypeObject*)obj->ob_type)->tp_name)); // NOLINT } void** vh = inst->simple_layout ? inst->simple_value_holder : &inst->nonsimple.values_and_holders[0]; attrs[key] = reinterpret_cast(vh[0]); } void CastPyArg2AttrIRBlock(PyObject* obj, paddle::framework::AttributeMap& attrs, // NOLINT const std::string& key, const std::string& op_type, ssize_t arg_pos) { VLOG(3) << "After Process pir::Block*"; ::pybind11::detail::instance* inst = (::pybind11::detail::instance*)obj; // NOLINT void** vh = inst->simple_layout ? inst->simple_value_holder : &inst->nonsimple.values_and_holders[0]; attrs[key] = reinterpret_cast(vh[0]); } void CastPyArg2AttrIRProgram(PyObject* obj, paddle::framework::AttributeMap& attrs, // NOLINT const std::string& key, const std::string& op_type, ssize_t arg_pos) { VLOG(3) << "After Process pir::Program*"; const std::shared_ptr program = ::py::handle(obj).cast>(); attrs[key] = program; } void CastPyArg2AttrValues(PyObject* obj, paddle::framework::AttributeMap& attrs, // NOLINT const std::string& key, const std::string& op_type, ssize_t arg_pos) { std::vector results; if (PyList_Check(obj)) { Py_ssize_t len = PyList_Size(obj); PyObject* item = nullptr; for (Py_ssize_t i = 0; i < len; i++) { // TODO(xiongkun): judge Value; item = PyList_GetItem(obj, i); ::pybind11::detail::instance* inst = (::pybind11::detail::instance*)item; // NOLINT void** vh = inst->simple_layout ? inst->simple_value_holder : &inst->nonsimple.values_and_holders[0]; pir::Value* value = reinterpret_cast(vh[0]); results.emplace_back(pir::Value(value->impl())); } } else { PADDLE_THROW(common::errors::InvalidType( "%s(): argument (position %d) must be " "a list of int, float, complex, or bool, but got %s", op_type, arg_pos + 1, ((PyTypeObject*)obj->ob_type)->tp_name)); // NOLINT } attrs[key] = results; VLOG(4) << "Pybind: Cast " << results.size() << " Value Finished."; } void ConstructAttrMapFromPyArgs( const std::string& op_type, PyObject* args, ssize_t attr_start, ssize_t attr_end, paddle::framework::AttributeMap& attrs) { // NOLINT PADDLE_ENFORCE_EQ((attr_end - attr_start) % 2, 0, common::errors::InvalidArgument( "The number of arguments for attributes should be even " "but attr_start = %d, attr_end = %d.", attr_start, attr_end)); auto attr_type_map = &(OpAttrTypeMap::Instance().Map()[op_type]); PyObject* obj = nullptr; for (ssize_t arg_pos = attr_start; arg_pos < attr_end; arg_pos += 2) { VLOG(5) << "Start Process " << arg_pos; Py_ssize_t key_len = 0; const char* key_ptr = nullptr; obj = PyTuple_GET_ITEM(args, arg_pos); if (PyObject_CheckString(obj)) { key_ptr = PyUnicode_AsUTF8AndSize(obj, &key_len); } else { PADDLE_THROW(common::errors::InvalidArgument( "%s(): argument (position %d) must be str, but got " "%s", op_type, arg_pos, ((PyTypeObject*)obj->ob_type)->tp_name)); // NOLINT } std::string key(key_ptr, (size_t)key_len); // NOLINT VLOG(5) << "Start Process " << key; auto iter = attr_type_map->find(key); if (iter == attr_type_map->end()) { continue; } obj = PyTuple_GET_ITEM(args, arg_pos + 1); switch (iter->second) { case paddle::framework::proto::AttrType::INT: CastPyArg2AttrInt(obj, attrs, key, op_type, arg_pos); break; case paddle::framework::proto::AttrType::FLOAT: CastPyArg2AttrFloat(obj, attrs, key, op_type, arg_pos); break; case paddle::framework::proto::AttrType::FLOAT64: CastPyArg2AttrDouble(obj, attrs, key, op_type, arg_pos); break; case paddle::framework::proto::AttrType::STRING: CastPyArg2AttrString(obj, attrs, key, op_type, arg_pos); break; case paddle::framework::proto::AttrType::INTS: CastPyArg2AttrInts(obj, attrs, key, op_type, arg_pos); break; case paddle::framework::proto::AttrType::FLOATS: CastPyArg2AttrFloats(obj, attrs, key, op_type, arg_pos); break; case paddle::framework::proto::AttrType::STRINGS: CastPyArg2AttrStrings(obj, attrs, key, op_type, arg_pos); break; case paddle::framework::proto::AttrType::BOOLEAN: CastPyArg2AttrBoolean(obj, attrs, key, op_type, arg_pos); break; case paddle::framework::proto::AttrType::BOOLEANS: CastPyArg2AttrBooleans(obj, attrs, key, op_type, arg_pos); break; case paddle::framework::proto::AttrType::LONG: CastPyArg2AttrLong(obj, attrs, key, op_type, arg_pos); break; case paddle::framework::proto::AttrType::LONGS: CastPyArg2AttrLongs(obj, attrs, key, op_type, arg_pos); break; case paddle::framework::proto::AttrType::FLOAT64S: CastPyArg2AttrFloat64s(obj, attrs, key, op_type, arg_pos); break; case paddle::framework::proto::AttrType::BLOCK: CastPyArg2AttrBlock(obj, attrs, key, op_type, arg_pos); break; case paddle::framework::proto::AttrType::SCALAR: CastPyArg2AttrScalar(obj, attrs, key, op_type, arg_pos); break; case paddle::framework::proto::AttrType::SCALARS: CastPyArg2AttrScalars(obj, attrs, key, op_type, arg_pos); break; default: break; } } } void ConstructAttrMapForLegacyRunProgram( const std::string& op_type, PyObject* args, ssize_t attr_start, ssize_t attr_end, paddle::framework::AttributeMap& attrs) { // NOLINT PADDLE_ENFORCE_EQ((attr_end - attr_start) % 2, 0, common::errors::InvalidArgument( "The number of arguments for attributes should be even " "but attr_start = %d, attr_end = %d.", attr_start, attr_end)); using CastFuncType = void (*)(PyObject*, paddle::framework::AttributeMap&, const std::string&, const std::string&, ssize_t); // Static map from keys to casting function pointers static const std::unordered_map kAttrFuncMap = { {"forward_global_block", CastPyArg2AttrBlock}, {"backward_global_block", CastPyArg2AttrBlock}, {"is_test", CastPyArg2AttrBoolean}, {"program_id", CastPyArg2AttrLong}, {"param_grad_names", CastPyArg2AttrStrings}, {"x_names", CastPyArg2AttrStrings}, {"out_grad_names", CastPyArg2AttrStrings}, {"x_grad_names", CastPyArg2AttrStrings}, {"in_pir_pt_mode", CastPyArg2AttrBoolean}, {"use_interpretorcore", CastPyArg2AttrBoolean}, {"global_block", CastPyArg2AttrBlock}, {"start_op_index", CastPyArg2AttrLong}, {"end_op_index", CastPyArg2AttrLong}, }; PyObject* obj = nullptr; for (ssize_t arg_pos = attr_start; arg_pos < attr_end; arg_pos += 2) { VLOG(3) << "Start Process " << arg_pos; Py_ssize_t key_len = 0; const char* key_ptr = nullptr; obj = PyTuple_GET_ITEM(args, arg_pos); if (PyObject_CheckString(obj)) { key_ptr = PyUnicode_AsUTF8AndSize(obj, &key_len); } else { PADDLE_THROW(common::errors::InvalidArgument( "%s(): argument (position %d) must be str, but got %s", op_type, arg_pos, ((PyTypeObject*)obj->ob_type)->tp_name)); // NOLINT } std::string_view key_view(key_ptr, static_cast(key_len)); VLOG(3) << "Start Process " << key_view; obj = PyTuple_GET_ITEM(args, arg_pos + 1); auto it = kAttrFuncMap.find(std::string(key_view)); if (it != kAttrFuncMap.end()) { // Call Cast function it->second(obj, attrs, std::string(key_view), op_type, arg_pos); } else { PADDLE_THROW(common::errors::InvalidArgument( "Attribute key %.*s is not recognized for operator %s.", static_cast(key_view.size()), key_view.data(), op_type.c_str())); // NOLINT } } } PyObject* ConstructProgramAttrMapForRunProgram(PyObject* self, PyObject* args) { const std::string op_type = "run_program"; PyObject* attrs_dict = nullptr; if (!PyArg_ParseTuple(args, "O", &attrs_dict)) { return nullptr; } paddle::framework::AttributeMap* attrs_ptr = new (std::nothrow) paddle::framework::AttributeMap(); if (!attrs_ptr) { PADDLE_THROW(common::errors::InvalidArgument( "%s(): failed to allocate memory for AttributeMap.", op_type)); } ConstructAttrMapForRunProgram(op_type, attrs_dict, *attrs_ptr); PyObject* py_attrs_capsule = PyCapsule_New( attrs_ptr, "paddle.framework.AttributeMap", [](PyObject* capsule) { paddle::framework::AttributeMap* data = reinterpret_cast( PyCapsule_GetPointer(capsule, "paddle.framework.AttributeMap")); if (data) { delete data; } }); if (!py_attrs_capsule) { delete attrs_ptr; PyErr_SetString(PyExc_RuntimeError, "Failed to create PyCapsule for AttributeMap."); return nullptr; } return py_attrs_capsule; } void ConstructCudaGraphAttrMapForRunProgram( const std::string& op_type, PyObject* args, ssize_t arg_pos, paddle::framework::AttributeMap& attrs) { // NOLINT PyObject* attrs_dict = PyTuple_GET_ITEM(args, arg_pos); ConstructAttrMapForRunProgram(op_type, attrs_dict, attrs); } void ConstructAttrMapForRunProgram( const std::string& op_type, PyObject* attrs_dict, paddle::framework::AttributeMap& attrs) { // NOLINT if (!PyDict_Check(attrs_dict)) { PADDLE_THROW(common::errors::InvalidArgument( "%s(): argument must be dict, but got %s", op_type, reinterpret_cast(attrs_dict->ob_type)->tp_name)); } using CastFuncType = void (*)(PyObject*, paddle::framework::AttributeMap&, const std::string&, const std::string&, ssize_t); // Static map from keys to casting function pointers static const std::unordered_map kAttrFuncMap = { {"forward_program", CastPyArg2AttrIRProgram}, {"backward_program", CastPyArg2AttrIRProgram}, {"is_test", CastPyArg2AttrBoolean}, {"in_sot_mode", CastPyArg2AttrBoolean}, {"program_id", CastPyArg2AttrLong}, {"fo_values", CastPyArg2AttrValues}, {"fx_names", CastPyArg2AttrStrings}, {"fp_names", CastPyArg2AttrStrings}, {"fm_names", CastPyArg2AttrStrings}, {"fo_names", CastPyArg2AttrStrings}, {"bx_names", CastPyArg2AttrStrings}, {"bp_names", CastPyArg2AttrStrings}, {"bm_names", CastPyArg2AttrStrings}, {"bo_names", CastPyArg2AttrStrings}, {"bx_g_names", CastPyArg2AttrStrings}, {"bp_g_names", CastPyArg2AttrStrings}, {"bo_g_names", CastPyArg2AttrStrings}, {"no_need_buffers_names", CastPyArg2AttrStrings}, {"cuda_graph_state", CastPyArg2AttrLong}, {"cuda_graph_dispatch_key", CastPyArg2AttrLong}, }; PyObject *key, *value; Py_ssize_t pos = 0; while (PyDict_Next(attrs_dict, &pos, &key, &value)) { Py_ssize_t key_len = 0; const char* key_ptr = nullptr; if (PyObject_CheckString(key)) { key_ptr = PyUnicode_AsUTF8AndSize(key, &key_len); } else { PADDLE_THROW(common::errors::InvalidArgument( "%s(): dict key must be str, but got %s", op_type, reinterpret_cast(key->ob_type)->tp_name)); } std::string_view key_view(key_ptr, static_cast(key_len)); auto it = kAttrFuncMap.find(std::string(key_view)); if (it != kAttrFuncMap.end()) { it->second(value, attrs, std::string(key_view), op_type, 0); } else { PADDLE_THROW(common::errors::InvalidArgument( "Attribute key %.*s is not recognized for operator %s.", static_cast(key_view.size()), key_view.data(), op_type.c_str())); } } } unsigned long GetUnsignedLongFromArgs( // NOLINT const std::string& op_type, const std::string& arg_name, PyObject* args, ssize_t arg_idx, bool dispensable) { PyObject* item = PyTuple_GET_ITEM(args, arg_idx); if (item == nullptr) { if (!dispensable) { PADDLE_THROW(common::errors::InvalidArgument( "%s(): argument '%s' (position %d) must be long, but got None", op_type, arg_name, arg_idx)); } return 0; } if (PyObject_CheckLong(item)) { return PyObject_ToUInt64(item); } else { PADDLE_THROW(common::errors::InvalidArgument( "%s(): argument '%s' (position %d) must be " "long, but got %s", op_type, arg_name, arg_idx, ((PyTypeObject*)item->ob_type)->tp_name)); // NOLINT } } void InitOpsAttrTypeMap() { auto op_info_map = paddle::framework::OpInfoMap::Instance().map(); for (auto& item : op_info_map) { auto op_proto = item.second.proto_; if (op_proto == nullptr) { continue; } auto attrs_proto = op_proto->attrs(); for (auto& attr : attrs_proto) { OpAttrTypeMap::Instance().Map()[item.first][attr.name()] = attr.type(); } } const auto& extra_attr_maps = operators::ExtraInfoUtils::Instance().GetAllExtraAttrsMap(); for (const auto& extra_attrs : extra_attr_maps) { for (auto& attr : extra_attrs.second) { OpAttrTypeMap::Instance().Map()[extra_attrs.first][attr.first] = static_cast(attr.second.index() - 1); } } } ssize_t GetIdxFromCoreOpsInfoMap( const std::unordered_map>& core_ops_info_map, const std::string& op_type, const std::string& name) { // `core_ops_info_map` can be `core_ops_args_info` or // `core_ops_returns_info`. `core_ops_args_info`: get index from // core_ops_args_info[op_type] according to input name. // `core_ops_returns_info`: get index from core_ops_returns_info[op_type] // according to return name. if (!core_ops_info_map.count(op_type)) { PADDLE_THROW(common::errors::Fatal( "Op %s is not found in core_ops_*_info map.", op_type)); } else { auto args_list = core_ops_info_map.at(op_type); auto it = std::find(args_list.begin(), args_list.end(), name); if (it == args_list.end()) { PADDLE_THROW(common::errors::Fatal( "%s is not found in op %s's args.", name, op_type)); } else { return std::distance(args_list.begin(), it); } } return -1; } static PyMethodDef OpFunctionCommonMethods[] = { // NOLINT {"construct_program_attribute_map", (PyCFunction)ConstructProgramAttrMapForRunProgram, METH_VARARGS, "create attribute map for run program"}, {nullptr, nullptr, 0, nullptr}}; void BindOpFunctionCommon(PyObject* module) { if (PyModule_AddFunctions(module, OpFunctionCommonMethods) < 0) { PADDLE_THROW(common::errors::Fatal( "Init Paddle error in BindOpFunctionCommon(PyModule_AddFunctions).")); return; } } // For parse argruments from args and kwargs // Get item from PyObject* args or PyObject* kwargs PyObject* GetItemFromArgsOrKWArgs(PyObject* args, int pos, PyObject* kwargs, const std::vector& keywords, int nargs, int* remaining_kwargs, bool dispensable) { // get item from args first if pos < nargs if (pos < nargs) { PyObject* arg = PyTuple_GetItem(args, pos); if (arg) { return arg; } } else { // get item from kwargs if (kwargs) { PyObject* arg = nullptr; for (const std::string& keyword : keywords) { arg = PyDict_GetItemString(kwargs, keyword.c_str()); if (arg) { *remaining_kwargs = *remaining_kwargs - 1; return arg; } } } } if (!dispensable) { PADDLE_THROW(common::errors::InvalidArgument( "Argument '%s' (position %d) must be provided", keywords[0], pos)); } return nullptr; } void CheckRemainingParamsValidity(PyObject* args, PyObject* kwargs, int remaining_kwargs, int nargs, bool inplace) { const std::string ignored_arg_name = "name"; const std::string ignored_arg_out = "out"; if (remaining_kwargs == 0) return; PyObject* name = PyDict_GetItemString(kwargs, ignored_arg_name.c_str()); PyObject* out = PyDict_GetItemString(kwargs, ignored_arg_out.c_str()); if (inplace) { if (remaining_kwargs == 1 && name) return; } else { if (remaining_kwargs == 1 && (name || out)) return; if (remaining_kwargs == 2 && (name && out)) return; } PADDLE_THROW(common::errors::InvalidArgument("has too many arguments")); return; } } // namespace paddle::pybind