void pb_num_feature::add_feature( const std::string& key, double value, std::vector<std::pair<std::string, double> >& ret_fv) const { scoped_gil lk; pb_object pkey(pb_unicode_from_string(key)); PB_CHECK(pkey, "cannot convert input key to Python object: " << key); pb_object pval(PyFloat_FromDouble(value)); PB_CHECK(pval, "cannot convert input value to Python object for key: " << key); pb_object ret(PyObject_CallMethodObjArgs( ins_.get(), method_.get(), pkey.get(), pval.get(), NULL)); PB_CHECK(ret, name_ << " method cannot be called"); PB_CHECK(PyList_CheckExact(ret.get()), name_ << " method returned non-list type: " << pb_str(ret.get())); size_t size = PyList_Size(ret.get()); for (size_t i = 0; i < size; ++i) { PyObject* tpl = PyList_GetItem(ret.get(), i); PB_CHECK(tpl, "item " << i << " cannot be accessed: " << pb_str(ret.get())); PB_CHECK(PyTuple_CheckExact(tpl), "list must not contain non-tuple: " << pb_str(tpl)); PB_CHECK(PyTuple_Size(tpl) == 2, "tuple length must be 2: " << pb_str(tpl)); PyObject* f_key = PyTuple_GetItem(tpl, 0); PyObject* f_val = PyTuple_GetItem(tpl, 1); PB_CHECK(PyUnicode_CheckExact(f_key), "feature key must be a unicode string: " << pb_str(tpl)); PB_CHECK(PyNumber_Check(f_val), "feature value must be a number: " << pb_str(tpl)); pb_object f_key_enc(PyUnicode_AsUTF8String(f_key)); PB_CHECK(f_key_enc, "feature key cannot be encoded as UTF-8: " << pb_str(tpl)); pb_object f_val_float(PyNumber_Float(f_val)); PB_CHECK(f_val_float, "value cannot be converted as float: " << pb_str(tpl)); ret_fv.push_back(std::make_pair( std::string(PyBytes_AsString(f_key_enc.get())), PyFloat_AsDouble(f_val_float.get()))); } }
explicit pb_num_feature(PyObject* ins) : name_("extract"), ins_(ins), method_(pb_unicode_from_string(name_)) {}