py_decimal.cpp 1.7 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859
  1. #include "py_decimal.h"
  2. #include "py_errors.h"
  3. #include "py_utils.h"
  4. #include "py_cast.h"
  5. #include <util/stream/str.h>
  6. #include <yql/essentials/public/udf/udf_value.h>
  7. using namespace NKikimr;
  8. namespace NPython {
  9. TPyObjectPtr ToPyDecimal(const TPyCastContext::TPtr& ctx, const NKikimr::NUdf::TUnboxedValuePod& value, ui8 precision, ui8 scale)
  10. {
  11. const auto str = NYql::NDecimal::ToString(value.GetInt128(), precision, scale);
  12. PY_ENSURE(str, "Bad decimal value.");
  13. const TPyObjectPtr pyStr(PyRepr(str));
  14. const TPyObjectPtr args(PyTuple_Pack(1, pyStr.Get()));
  15. PY_ENSURE(args, "Can't pack args.");
  16. const TPyObjectPtr dec(PyObject_CallObject(ctx->GetDecimal().Get(), args.Get()));
  17. PY_ENSURE(dec, "Can't create Decimal.");
  18. return dec;
  19. }
  20. NKikimr::NUdf::TUnboxedValue FromPyDecimal(const TPyCastContext::TPtr& ctx, PyObject* value, ui8 precision, ui8 scale)
  21. {
  22. const TPyObjectPtr print(PyObject_Str(value));
  23. PY_ENSURE(print, "Can't print decimal.");
  24. TString str;
  25. PY_ENSURE(TryPyCast<TString>(print.Get(), str), "Can't get decimal string.");
  26. if (str.EndsWith("Infinity")) {
  27. str.resize(str.size() - 5U);
  28. }
  29. const auto dec = NYql::NDecimal::FromStringEx(str.c_str(), precision, scale);
  30. PY_ENSURE(!NYql::NDecimal::IsError(dec), "Can't make Decimal from string.");
  31. return NKikimr::NUdf::TUnboxedValuePod(dec);
  32. }
  33. const TPyObjectPtr& TPyCastContext::GetDecimal() {
  34. if (!Decimal) {
  35. const TPyObjectPtr module(PyImport_ImportModule("decimal"));
  36. PY_ENSURE(module, "Can't import decimal.");
  37. Decimal.ResetSteal(PyObject_GetAttrString(module.Get(), "Decimal"));
  38. PY_ENSURE(Decimal, "Can't get Decimal.");
  39. }
  40. return Decimal;
  41. }
  42. } // namespace NPython