| /* |
| * Licensed to the Apache Software Foundation (ASF) under one or more |
| * contributor license agreements. See the NOTICE file distributed with |
| * this work for additional information regarding copyright ownership. |
| * The ASF licenses this file to You 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 "module.h" |
| #include "utils.h" |
| |
| #include <ignite/common/detail/defer.h> |
| |
| #include <Python.h> |
| |
| #define LAZY_INIT_MODULE_CLASS(class_name) \ |
| static PyObject* instance{nullptr}; \ |
| if (!instance) \ |
| instance = py_get_module_class(class_name); \ |
| return instance |
| |
| |
| void set_error(const ignite::ignite_error &error) { |
| auto error_class = py_get_module_interface_error_class(); |
| |
| switch (error.get_status_code()) { |
| case ignite::error::code::NULLABLE_VALUE: |
| case ignite::error::code::CURSOR_ALREADY_CLOSED: |
| case ignite::error::code::ILLEGAL_ARGUMENT: { |
| error_class = py_get_module_interface_error_class(); |
| break; |
| } |
| |
| case ignite::error::code::RESOURCE_CLOSING: |
| case ignite::error::code::NODE_LEFT: |
| case ignite::error::code::COMPONENT_NOT_STARTED: |
| case ignite::error::code::NODE_STOPPING: { |
| error_class = py_get_module_database_error_class(); |
| break; |
| } |
| |
| case ignite::error::code::SSL_CONFIGURATION: |
| case ignite::error::code::USER_OBJECT_SERIALIZATION: |
| case ignite::error::code::INTERNAL: { |
| error_class = py_get_module_programming_error_class(); |
| break; |
| } |
| |
| case ignite::error::code::TABLE_ALREADY_EXISTS: |
| case ignite::error::code::TABLE_NOT_FOUND: |
| case ignite::error::code::COLUMN_ALREADY_EXISTS: |
| case ignite::error::code::COLUMN_NOT_FOUND: |
| case ignite::error::code::SCHEMA_VERSION_MISMATCH: |
| case ignite::error::code::UNSUPPORTED_PARTITION_TYPE: { |
| error_class = py_get_module_programming_error_class(); |
| break; |
| } |
| |
| case ignite::error::code::CONNECTION: |
| case ignite::error::code::PROTOCOL: |
| case ignite::error::code::PROTOCOL_COMPATIBILITY: |
| case ignite::error::code::TABLE_ID_NOT_FOUND: |
| case ignite::error::code::CONFIGURATION: |
| case ignite::error::code::CLUSTER_ID_MISMATCH: |
| case ignite::error::code::CLIENT_SSL_CONFIGURATION: |
| case ignite::error::code::HANDSHAKE_HEADER: |
| case ignite::error::code::SERVER_TO_CLIENT_REQUEST: { |
| error_class = py_get_module_operational_error_class(); |
| break; |
| } |
| |
| case ignite::error::code::QUERY_NO_RESULT_SET: |
| case ignite::error::code::SCHEMA_NOT_FOUND: |
| case ignite::error::code::STMT_PARSE: |
| case ignite::error::code::STMT_VALIDATION: |
| case ignite::error::code::EXECUTION_CANCELLED: |
| case ignite::error::code::RUNTIME: |
| case ignite::error::code::MAPPING: |
| case ignite::error::code::TX_CONTROL_INSIDE_EXTERNAL_TX: { |
| error_class = py_get_module_programming_error_class(); |
| break; |
| } |
| |
| case ignite::error::code::CONSTRAINT_VIOLATION: { |
| error_class = py_get_module_integrity_error_class(); |
| break; |
| } |
| |
| case ignite::error::code::STARTING_STORAGE: |
| case ignite::error::code::RESTORING_STORAGE: |
| case ignite::error::code::COMPACTION: |
| case ignite::error::code::OP_EXECUTION: |
| case ignite::error::code::OP_EXECUTION_TIMEOUT: |
| case ignite::error::code::COMPACTED: |
| case ignite::error::code::DIVERGED: { |
| error_class = py_get_module_database_error_class(); |
| break; |
| } |
| |
| case ignite::error::code::INDEX_NOT_FOUND: |
| case ignite::error::code::INDEX_ALREADY_EXISTS: { |
| error_class = py_get_module_database_error_class(); |
| break; |
| } |
| |
| case ignite::error::code::TX_STATE_STORAGE: |
| case ignite::error::code::TX_STATE_STORAGE_STOPPED: |
| case ignite::error::code::TX_UNEXPECTED_STATE: |
| case ignite::error::code::ACQUIRE_LOCK: |
| case ignite::error::code::ACQUIRE_LOCK_TIMEOUT: |
| case ignite::error::code::TX_COMMIT: |
| case ignite::error::code::TX_ROLLBACK: |
| case ignite::error::code::TX_FAILED_READ_WRITE_OPERATION: |
| case ignite::error::code::TX_STATE_STORAGE_REBALANCE: |
| case ignite::error::code::TX_READ_ONLY_TOO_OLD: |
| case ignite::error::code::TX_INCOMPATIBLE_SCHEMA: |
| case ignite::error::code::TX_PRIMARY_REPLICA_EXPIRED: |
| case ignite::error::code::TX_ALREADY_FINISHED: |
| case ignite::error::code::TX_STALE_OPERATION: |
| case ignite::error::code::TX_STALE_READ_ONLY_OPERATION: |
| case ignite::error::code::TX_ALREADY_FINISHED_WITH_EXCEPTION: |
| case ignite::error::code::TX_ALREADY_FINISHED_WITH_TIMEOUT: { |
| error_class = py_get_module_database_error_class(); |
| break; |
| } |
| |
| case ignite::error::code::REPLICA_COMMON: |
| case ignite::error::code::REPLICA_IS_ALREADY_STARTED: |
| case ignite::error::code::REPLICA_TIMEOUT: |
| case ignite::error::code::REPLICA_UNSUPPORTED_REQUEST: |
| case ignite::error::code::REPLICA_UNAVAILABLE: |
| case ignite::error::code::REPLICA_MISS: |
| case ignite::error::code::CURSOR_CLOSE: |
| case ignite::error::code::REPLICA_STOPPING: { |
| error_class = py_get_module_database_error_class(); |
| break; |
| } |
| |
| case ignite::error::code::INDEX_NOT_BUILT: |
| case ignite::error::code::STORAGE_CORRUPTED: { |
| error_class = py_get_module_database_error_class(); |
| break; |
| } |
| |
| case ignite::error::code::ZONE_NOT_FOUND: { |
| error_class = py_get_module_database_error_class(); |
| break; |
| } |
| |
| case ignite::error::code::UNRESOLVABLE_CONSISTENT_ID: |
| case ignite::error::code::BIND: |
| case ignite::error::code::RECIPIENT_LEFT: |
| case ignite::error::code::ADDRESS_UNRESOLVED: { |
| error_class = py_get_module_database_error_class(); |
| break; |
| } |
| |
| case ignite::error::code::CONFIG_READ: |
| case ignite::error::code::CONFIG_FILE_CREATE: |
| case ignite::error::code::CONFIG_WRITE: |
| case ignite::error::code::CONFIG_PARSE: { |
| error_class = py_get_module_database_error_class(); |
| break; |
| } |
| |
| case ignite::error::code::UNIT_NOT_FOUND: |
| case ignite::error::code::UNIT_ALREADY_EXISTS: |
| case ignite::error::code::UNIT_CONTENT_READ: |
| case ignite::error::code::UNIT_UNAVAILABLE: |
| case ignite::error::code::UNIT_ZIP: |
| case ignite::error::code::UNIT_WRITE: |
| case ignite::error::code::UNIT_NON_UNIQUE_FILENAMES: { |
| error_class = py_get_module_database_error_class(); |
| break; |
| } |
| |
| case ignite::error::code::CLOSED: { |
| error_class = py_get_module_database_error_class(); |
| break; |
| } |
| |
| case ignite::error::code::UNSUPPORTED_AUTHENTICATION_TYPE: |
| case ignite::error::code::INVALID_CREDENTIALS: |
| case ignite::error::code::BASIC_PROVIDER: { |
| error_class = py_get_module_database_error_class(); |
| break; |
| } |
| |
| case ignite::error::code::CLASS_PATH: |
| case ignite::error::code::CLASS_LOADER: |
| case ignite::error::code::CLASS_INITIALIZATION: |
| case ignite::error::code::QUEUE_OVERFLOW: |
| case ignite::error::code::COMPUTE_JOB_STATUS_TRANSITION: |
| case ignite::error::code::CANCELLING: |
| case ignite::error::code::RESULT_NOT_FOUND: |
| case ignite::error::code::FAIL_TO_GET_JOB_STATE: |
| case ignite::error::code::COMPUTE_JOB_FAILED: |
| case ignite::error::code::PRIMARY_REPLICA_RESOLVE: |
| case ignite::error::code::CHANGE_JOB_PRIORITY: |
| case ignite::error::code::NODE_NOT_FOUND: |
| case ignite::error::code::MARSHALLING_TYPE_MISMATCH: |
| case ignite::error::code::COMPUTE_JOB_CANCELLED: |
| case ignite::error::code::RESOURCE_NOT_FOUND: |
| case ignite::error::code::COMPUTE_PLATFORM_EXECUTOR: { |
| error_class = py_get_module_database_error_class(); |
| break; |
| } |
| |
| case ignite::error::code::VALIDATION: { |
| error_class = py_get_module_database_error_class(); |
| break; |
| } |
| |
| case ignite::error::code::PRIMARY_REPLICA_AWAIT_TIMEOUT: |
| case ignite::error::code::PRIMARY_REPLICA_AWAIT: { |
| error_class = py_get_module_database_error_class(); |
| break; |
| } |
| |
| case ignite::error::code::SYSTEM_WORKER_BLOCKED: |
| case ignite::error::code::SYSTEM_CRITICAL_OPERATION_TIMEOUT: { |
| error_class = py_get_module_database_error_class(); |
| break; |
| } |
| |
| case ignite::error::code::ILLEGAL_PARTITION_ID: |
| case ignite::error::code::NODES_NOT_FOUND: |
| case ignite::error::code::PARTITION_STATE: |
| case ignite::error::code::CLUSTER_NOT_IDLE: { |
| error_class = py_get_module_database_error_class(); |
| break; |
| } |
| |
| case ignite::error::code::CLUSTER_NOT_INITIALIZED: |
| case ignite::error::code::CLUSTER_INIT_FAILED: |
| case ignite::error::code::NODE_NOT_STARTED: |
| case ignite::error::code::NODE_START: { |
| error_class = py_get_module_database_error_class(); |
| break; |
| } |
| |
| case ignite::error::code::COMMON: |
| case ignite::error::code::UNSUPPORTED_OBJECT_TYPE: |
| case ignite::error::code::UNMARSHALLING: { |
| error_class = py_get_module_not_supported_error_class(); |
| break; |
| } |
| |
| case ignite::error::code::CLUSTER_NOT_INIT: { |
| error_class = py_get_module_database_error_class(); |
| break; |
| } |
| |
| case ignite::error::code::UNSUPPORTED_TABLE_BASED_REPLICATION: |
| case ignite::error::code::OPERATION_TIMEOUT: |
| case ignite::error::code::TX_DELAYED_ACK: |
| case ignite::error::code::GROUP_OVERLOADED: |
| case ignite::error::code::GROUP_UNAVAILABLE: |
| case ignite::error::code::EMPTY_DATA_NODES: |
| case ignite::error::code::JOIN_DENIED: |
| case ignite::error::code::EMPTY_ASSIGNMENTS: |
| case ignite::error::code::NOT_ENOUGH_ALIVE_NODES: |
| case ignite::error::code::ILLEGAL_NODES_SET: |
| case ignite::error::code::REQUEST_FORWARD: |
| case ignite::error::code::REMOTE_NODE: |
| case ignite::error::code::CONFIGURATION_APPLY: |
| case ignite::error::code::CONFIGURATION_PARSE: |
| case ignite::error::code::CONFIGURATION_VALIDATION: { |
| error_class = py_get_module_not_supported_error_class(); |
| break; |
| } |
| } |
| std::string error_str{error.what_str()}; |
| if (error.get_java_stack_trace()) { |
| error_str += "\n" + *error.get_java_stack_trace(); |
| } |
| PyErr_SetString(error_class, error_str.c_str()); |
| } |
| |
| std::string get_current_exception_as_string() { |
| auto err_obj = PyErr_Occurred(); |
| if (!err_obj) |
| return {}; |
| |
| auto err_str_obj = PyObject_Str(err_obj); |
| if (!err_str_obj) |
| return "<Can not cast exception to a string>"; |
| |
| auto *data = PyBytes_AsString(err_str_obj); |
| auto len = PyBytes_Size(err_str_obj); |
| return {data, std::size_t(len)}; |
| } |
| |
| const char* py_object_get_typename(const PyObject* obj) { |
| if (!obj || !obj->ob_type || !obj->ob_type->tp_name) { |
| return "Unknown"; |
| } |
| |
| return obj->ob_type->tp_name; |
| } |
| |
| PyObject* py_get_module() { |
| static PyObject* instance{nullptr}; |
| // No need for sync here - Python is single-threaded |
| if (!instance) { |
| instance = PyImport_ImportModule(MODULE_NAME); |
| } |
| return instance; |
| } |
| |
| PyObject* py_get_class(const char* module_name, const char* class_name) { |
| auto module_obj = PyImport_ImportModule(module_name); |
| if (!module_obj) |
| return nullptr; |
| |
| auto class_obj = PyObject_GetAttrString(module_obj, class_name); |
| Py_DECREF(module_obj); |
| |
| return class_obj; |
| } |
| |
| PyObject* py_get_module_class(const char* class_name) { |
| auto pyignite_dbapi_mod = py_get_module(); |
| if (!pyignite_dbapi_mod) |
| return nullptr; |
| |
| return PyObject_GetAttrString(pyignite_dbapi_mod, class_name); |
| } |
| |
| PyObject* py_call_method_no_arg(PyObject* obj, const char* method_name) { |
| PyObject* py_method_name = PyUnicode_FromString(method_name); |
| if (!py_method_name) |
| return nullptr; |
| auto py_method_name_guard = ignite::detail::defer([&]{ Py_DECREF(py_method_name); }); |
| |
| return PyObject_CallMethodObjArgs(obj, py_method_name, nullptr); |
| } |
| |
| std::int64_t py_get_attr_int(PyObject* obj, const char* attr_name) { |
| auto attr_obj = PyObject_GetAttrString(obj, attr_name); |
| if (!attr_obj) { |
| throw ignite::ignite_error(get_current_exception_as_string()); |
| } |
| auto attr_obj_guard = ignite::detail::defer([&] { Py_DECREF(attr_obj); }); |
| if (PyErr_Occurred()) { |
| throw ignite::ignite_error(get_current_exception_as_string()); |
| } |
| auto res = PyLong_AsLongLong(attr_obj); |
| if (PyErr_Occurred()) { |
| throw ignite::ignite_error(get_current_exception_as_string()); |
| } |
| return res; |
| } |
| |
| PyObject* py_get_module_uuid_class() { |
| LAZY_INIT_MODULE_CLASS("UUID"); |
| } |
| |
| PyObject* py_get_module_date_class() { |
| LAZY_INIT_MODULE_CLASS("DATE"); |
| } |
| |
| PyObject* py_get_module_time_class() { |
| LAZY_INIT_MODULE_CLASS("TIME"); |
| } |
| |
| PyObject* py_get_module_datetime_class() { |
| LAZY_INIT_MODULE_CLASS("DATETIME"); |
| } |
| |
| PyObject* py_get_module_timestamp_class() { |
| LAZY_INIT_MODULE_CLASS("TIMESTAMP"); |
| } |
| |
| PyObject* py_get_module_number_class() { |
| LAZY_INIT_MODULE_CLASS("NUMBER"); |
| } |
| |
| PyObject* py_get_module_duration_class() { |
| LAZY_INIT_MODULE_CLASS("DURATION"); |
| } |
| |
| PyObject* py_get_module_warning_class() { |
| LAZY_INIT_MODULE_CLASS("Warning"); |
| } |
| |
| PyObject* py_get_module_interface_error_class() { |
| LAZY_INIT_MODULE_CLASS("InterfaceError"); |
| } |
| |
| PyObject* py_get_module_database_error_class() { |
| LAZY_INIT_MODULE_CLASS("DatabaseError"); |
| } |
| |
| PyObject* py_get_module_data_error_class() { |
| LAZY_INIT_MODULE_CLASS("DataError"); |
| } |
| |
| PyObject* py_get_module_operational_error_class() { |
| LAZY_INIT_MODULE_CLASS("OperationalError"); |
| } |
| |
| PyObject* py_get_module_integrity_error_class() { |
| LAZY_INIT_MODULE_CLASS("IntegrityError"); |
| } |
| |
| PyObject* py_get_module_internal_error_class() { |
| LAZY_INIT_MODULE_CLASS("InternalError"); |
| } |
| |
| PyObject* py_get_module_programming_error_class() { |
| LAZY_INIT_MODULE_CLASS("ProgrammingError"); |
| } |
| |
| PyObject* py_get_module_not_supported_error_class() { |
| LAZY_INIT_MODULE_CLASS("NotSupportedError"); |
| } |
| |
| PyObject* py_create_uuid(ignite::bytes_view bytes) { |
| auto uuid_class = py_get_module_uuid_class(); |
| if (!uuid_class) |
| return nullptr; |
| |
| auto args = PyTuple_New(0); |
| if (!args) |
| return nullptr; |
| auto args_guard = ignite::detail::defer([&]{ Py_DECREF(args); }); |
| |
| auto kwargs = PyDict_New(); |
| if (!kwargs) |
| return nullptr; |
| auto kwargs_guard = ignite::detail::defer([&]{ Py_DECREF(kwargs); }); |
| |
| PyObject* py_bytes = PyBytes_FromStringAndSize(reinterpret_cast<const char*>(bytes.data()), bytes.size()); |
| if (!py_bytes) |
| return nullptr; |
| |
| if (PyDict_SetItemString(kwargs, "bytes", py_bytes) < 0) { |
| Py_DECREF(py_bytes); |
| return nullptr; |
| } |
| |
| return PyObject_Call(uuid_class, args, kwargs); |
| } |
| |
| PyObject* py_create_date(const ignite::ignite_date &value) { |
| auto date_class = py_get_module_date_class(); |
| if (!date_class) |
| return nullptr; |
| |
| PyObject* year = PyLong_FromLong(value.get_year()); |
| if (!year) |
| return nullptr; |
| auto year_guard = ignite::detail::defer([&]{ Py_DECREF(year); }); |
| |
| PyObject* month = PyLong_FromLong(value.get_month()); |
| if (!month) |
| return nullptr; |
| auto month_guard = ignite::detail::defer([&]{ Py_DECREF(month); }); |
| |
| PyObject* day = PyLong_FromLong(value.get_day_of_month()); |
| if (!day) |
| return nullptr; |
| auto day_guard = ignite::detail::defer([&]{ Py_DECREF(day); }); |
| |
| auto args = PyTuple_Pack(3, year, month, day); |
| if (!args) |
| return nullptr; |
| auto args_guard = ignite::detail::defer([&]{ Py_DECREF(args); }); |
| |
| year_guard.release(); |
| month_guard.release(); |
| day_guard.release(); |
| |
| auto kwargs = PyDict_New(); |
| if (!kwargs) |
| return nullptr; |
| auto kwargs_guard = ignite::detail::defer([&]{ Py_DECREF(kwargs); }); |
| |
| return PyObject_Call(date_class, args, kwargs); |
| } |
| |
| PyObject* py_create_time(const ignite::ignite_time &value) { |
| auto time_class = py_get_module_time_class(); |
| if (!time_class) |
| return nullptr; |
| |
| PyObject* hour = PyLong_FromLong(value.get_hour()); |
| if (!hour) |
| return nullptr; |
| auto hour_guard = ignite::detail::defer([&]{ Py_DECREF(hour); }); |
| |
| PyObject* minute = PyLong_FromLong(value.get_minute()); |
| if (!minute) |
| return nullptr; |
| auto minute_guard = ignite::detail::defer([&]{ Py_DECREF(minute); }); |
| |
| PyObject* second = PyLong_FromLong(value.get_second()); |
| if (!second) |
| return nullptr; |
| auto second_guard = ignite::detail::defer([&]{ Py_DECREF(second); }); |
| |
| PyObject* u_second = PyLong_FromLong(value.get_nano() / 1000); |
| if (!u_second) |
| return nullptr; |
| auto u_second_guard = ignite::detail::defer([&]{ Py_DECREF(u_second); }); |
| |
| auto args = PyTuple_Pack(4, hour, minute, second, u_second); |
| if (!args) |
| return nullptr; |
| auto args_guard = ignite::detail::defer([&]{ Py_DECREF(args); }); |
| |
| hour_guard.release(); |
| minute_guard.release(); |
| second_guard.release(); |
| u_second_guard.release(); |
| |
| auto kwargs = PyDict_New(); |
| if (!kwargs) |
| return nullptr; |
| auto kwargs_guard = ignite::detail::defer([&]{ Py_DECREF(kwargs); }); |
| |
| return PyObject_Call(time_class, args, kwargs); |
| } |
| |
| PyObject* py_create_datetime(const ignite::ignite_date_time &value) { |
| auto datetime_class = py_get_module_datetime_class(); |
| if (!datetime_class) |
| return nullptr; |
| |
| PyObject* year = PyLong_FromLong(value.get_year()); |
| if (!year) |
| return nullptr; |
| auto year_guard = ignite::detail::defer([&]{ Py_DECREF(year); }); |
| |
| PyObject* month = PyLong_FromLong(value.get_month()); |
| if (!month) |
| return nullptr; |
| auto month_guard = ignite::detail::defer([&]{ Py_DECREF(month); }); |
| |
| PyObject* day = PyLong_FromLong(value.get_day_of_month()); |
| if (!day) |
| return nullptr; |
| auto day_guard = ignite::detail::defer([&]{ Py_DECREF(day); }); |
| |
| PyObject* hour = PyLong_FromLong(value.get_hour()); |
| if (!hour) |
| return nullptr; |
| auto hour_guard = ignite::detail::defer([&]{ Py_DECREF(hour); }); |
| |
| PyObject* minute = PyLong_FromLong(value.get_minute()); |
| if (!minute) |
| return nullptr; |
| auto minute_guard = ignite::detail::defer([&]{ Py_DECREF(minute); }); |
| |
| PyObject* second = PyLong_FromLong(value.get_second()); |
| if (!second) |
| return nullptr; |
| auto second_guard = ignite::detail::defer([&]{ Py_DECREF(second); }); |
| |
| PyObject* u_second = PyLong_FromLong(value.get_nano() / 1000); |
| if (!u_second) |
| return nullptr; |
| auto u_second_guard = ignite::detail::defer([&]{ Py_DECREF(u_second); }); |
| |
| auto args = PyTuple_Pack(7, year, month, day, hour, minute, second, u_second); |
| if (!args) |
| return nullptr; |
| auto args_guard = ignite::detail::defer([&]{ Py_DECREF(args); }); |
| |
| year_guard.release(); |
| month_guard.release(); |
| day_guard.release(); |
| hour_guard.release(); |
| minute_guard.release(); |
| second_guard.release(); |
| u_second_guard.release(); |
| |
| auto kwargs = PyDict_New(); |
| if (!kwargs) |
| return nullptr; |
| auto kwargs_guard = ignite::detail::defer([&]{ Py_DECREF(kwargs); }); |
| |
| return PyObject_Call(datetime_class, args, kwargs); |
| } |
| |
| PyObject* py_create_datetime(const ignite::ignite_timestamp &value) { |
| auto datetime_class = py_get_module_datetime_class(); |
| if (!datetime_class) |
| return nullptr; |
| |
| PyObject* second = PyLong_FromLongLong(value.get_epoch_second()); |
| if (!second) |
| return nullptr; |
| auto second_guard = ignite::detail::defer([&]{ Py_DECREF(second); }); |
| |
| PyObject* u_second = PyLong_FromLongLong(value.get_nano() / 1000); |
| if (!u_second) |
| return nullptr; |
| auto u_second_guard = ignite::detail::defer([&]{ Py_DECREF(u_second); }); |
| |
| PyObject* constructor_name = PyUnicode_FromString("fromtimestamp"); |
| if (!constructor_name) |
| return nullptr; |
| auto constructor_name_guard = ignite::detail::defer([&]{ Py_DECREF(constructor_name); }); |
| |
| return PyObject_CallMethodObjArgs(datetime_class, constructor_name, second, nullptr); |
| } |
| |
| PyObject* py_create_number(std::string_view value) { |
| auto number_class = py_get_module_number_class(); |
| if (!number_class) |
| return nullptr; |
| |
| PyObject* str_obj = PyUnicode_FromStringAndSize(value.data(), value.size()); |
| if (!str_obj) |
| return nullptr; |
| auto str_obj_guard = ignite::detail::defer([&]{ Py_DECREF(str_obj); }); |
| |
| auto args = PyTuple_Pack(1, str_obj); |
| if (!args) |
| return nullptr; |
| auto args_guard = ignite::detail::defer([&]{ Py_DECREF(args); }); |
| |
| str_obj_guard.release(); |
| |
| auto kwargs = PyDict_New(); |
| if (!kwargs) |
| return nullptr; |
| auto kwargs_guard = ignite::detail::defer([&]{ Py_DECREF(kwargs); }); |
| |
| return PyObject_Call(number_class, args, kwargs); |
| } |
| |
| PyObject* py_create_timedelta(const ignite::ignite_duration &value) { |
| auto duration_class = py_get_module_duration_class(); |
| if (!duration_class) |
| return nullptr; |
| |
| auto args = PyTuple_New(0); |
| if (!args) |
| return nullptr; |
| auto args_guard = ignite::detail::defer([&]{ Py_DECREF(args); }); |
| |
| PyObject* second = PyLong_FromLong(value.get_seconds()); |
| if (!second) |
| return nullptr; |
| auto second_guard = ignite::detail::defer([&]{ Py_DECREF(second); }); |
| |
| PyObject* u_second = PyLong_FromLong(value.get_nano() / 1000); |
| if (!u_second) |
| return nullptr; |
| auto u_second_guard = ignite::detail::defer([&]{ Py_DECREF(u_second); }); |
| |
| auto kwargs = PyDict_New(); |
| if (!kwargs) |
| return nullptr; |
| auto kwargs_guard = ignite::detail::defer([&]{ Py_DECREF(kwargs); }); |
| |
| if (PyDict_SetItemString(kwargs, "seconds", second) < 0) |
| return nullptr; |
| second_guard.release(); |
| |
| if (PyDict_SetItemString(kwargs, "microseconds", u_second) < 0) |
| return nullptr; |
| u_second_guard.release(); |
| |
| return PyObject_Call(duration_class, args, kwargs); |
| } |