This is an automated email from the ASF dual-hosted git repository.
isapego pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/ignite-3.git
The following commit(s) were added to refs/heads/main by this push:
new de11d33ff1 IGNITE-22747 Python Client: add tox.ini for CI/CD (#4289)
de11d33ff1 is described below
commit de11d33ff168f3f5df362b5dbf6e8a2068559c12
Author: Igor Sapego <[email protected]>
AuthorDate: Mon Sep 2 16:00:44 2024 +0400
IGNITE-22747 Python Client: add tox.ini for CI/CD (#4289)
---
modules/platforms/python/cpp_module/CMakeLists.txt | 3 +
modules/platforms/python/cpp_module/module.cpp | 131 +++++++++++----------
.../platforms/python/cpp_module/py_connection.cpp | 6 +-
modules/platforms/python/cpp_module/py_cursor.cpp | 6 +-
modules/platforms/python/pyignite3/__init__.py | 55 ++++-----
modules/platforms/python/setup.py | 2 +-
modules/platforms/python/tox.ini | 30 +++++
7 files changed, 138 insertions(+), 95 deletions(-)
diff --git a/modules/platforms/python/cpp_module/CMakeLists.txt
b/modules/platforms/python/cpp_module/CMakeLists.txt
index 4c08dcb220..bb7ca0cf6b 100644
--- a/modules/platforms/python/cpp_module/CMakeLists.txt
+++ b/modules/platforms/python/cpp_module/CMakeLists.txt
@@ -54,4 +54,7 @@ if (WIN32)
set_target_properties(${TARGET} PROPERTIES SUFFIX ".pyd")
target_link_libraries(${TARGET} ${Python3_LIBRARIES})
remove_definitions(-DUNICODE=1)
+else()
+ set_target_properties(${TARGET} PROPERTIES PREFIX "")
endif()
+
diff --git a/modules/platforms/python/cpp_module/module.cpp
b/modules/platforms/python/cpp_module/module.cpp
index 1a068b0420..9a7223e21b 100644
--- a/modules/platforms/python/cpp_module/module.cpp
+++ b/modules/platforms/python/cpp_module/module.cpp
@@ -28,71 +28,10 @@
#include <Python.h>
-PyObject* connect(PyObject* self, PyObject *args, PyObject* kwargs);
-
-static PyMethodDef methods[] = {
- {"connect", (PyCFunction) connect, METH_VARARGS | METH_KEYWORDS, nullptr},
- {nullptr, nullptr, 0, nullptr} /* Sentinel */
-};
-
-static struct PyModuleDef module_def = {
- PyModuleDef_HEAD_INIT,
- MODULE_NAME,
- nullptr, /* m_doc */
- -1, /* m_size */
- methods, /* m_methods */
- nullptr, /* m_slots */
- nullptr, /* m_traverse */
- nullptr, /* m_clear */
- nullptr, /* m_free */
-};
-
-PyMODINIT_FUNC PyInit__pyignite3_extension(void) { //
NOLINT(*-reserved-identifier)
- PyObject* mod;
-
- mod = PyModule_Create(&module_def);
- if (mod == nullptr)
- return nullptr;
-
- if (prepare_py_connection_type() || prepare_py_cursor_type())
- return nullptr;
-
- if (register_py_connection_type(mod) || register_py_cursor_type(mod))
- return nullptr;
-
- return mod;
-}
-
-bool check_errors(ignite::diagnosable& diag) {
- auto &records = diag.get_diagnostic_records();
- if (records.is_successful())
- return true;
-
- std::string err_msg;
- switch (records.get_return_code()) {
- case SQL_INVALID_HANDLE:
- err_msg = "Invalid object handle";
- break;
-
- case SQL_NO_DATA:
- err_msg = "No data available";
- break;
-
- case SQL_ERROR:
- auto record = records.get_status_record(1);
- err_msg = record.get_message_text();
- break;
- }
-
- // TODO: IGNITE-22226 Set a proper error here, not a standard one.
- PyErr_SetString(PyExc_RuntimeError, err_msg.c_str());
-
- return false;
-}
-
static PyObject* make_connection(std::unique_ptr<ignite::sql_environment> env,
- std::unique_ptr<ignite::sql_connection> conn) {
- auto pyignite3_mod = PyImport_ImportModule("pyignite3");
+ std::unique_ptr<ignite::sql_connection> conn)
+{
+ auto pyignite3_mod = PyImport_ImportModule("pyignite3");
if (!pyignite3_mod)
return nullptr;
@@ -124,7 +63,7 @@ static PyObject*
make_connection(std::unique_ptr<ignite::sql_environment> env,
return conn_obj;
}
-static PyObject* connect(PyObject* self, PyObject* args, PyObject* kwargs) {
+static PyObject* pyignite3_connect(PyObject* self, PyObject* args, PyObject*
kwargs) {
static char *kwlist[] = {
"address",
"identity",
@@ -193,4 +132,66 @@ static PyObject* connect(PyObject* self, PyObject* args,
PyObject* kwargs) {
return make_connection(std::move(sql_env), std::move(sql_conn));
}
+static PyMethodDef methods[] = {
+ {"connect", (PyCFunction)pyignite3_connect, METH_VARARGS | METH_KEYWORDS,
nullptr},
+ {nullptr, nullptr, 0, nullptr} /* Sentinel */
+};
+
+static struct PyModuleDef module_def = {
+ PyModuleDef_HEAD_INIT,
+ MODULE_NAME,
+ nullptr, /* m_doc */
+ -1, /* m_size */
+ methods, /* m_methods */
+ nullptr, /* m_slots */
+ nullptr, /* m_traverse */
+ nullptr, /* m_clear */
+ nullptr, /* m_free */
+};
+
+PyMODINIT_FUNC PyInit__pyignite3_extension(void) { //
NOLINT(*-reserved-identifier)
+ PyObject* mod;
+
+ mod = PyModule_Create(&module_def);
+ if (mod == nullptr)
+ return nullptr;
+
+ if (prepare_py_connection_type() || prepare_py_cursor_type())
+ return nullptr;
+
+ if (register_py_connection_type(mod) || register_py_cursor_type(mod))
+ return nullptr;
+
+ return mod;
+}
+
+bool check_errors(ignite::diagnosable& diag) {
+ auto &records = diag.get_diagnostic_records();
+ if (records.is_successful())
+ return true;
+
+ std::string err_msg;
+ switch (records.get_return_code()) {
+ case SQL_INVALID_HANDLE:
+ err_msg = "Invalid object handle";
+ break;
+
+ case SQL_NO_DATA:
+ err_msg = "No data available";
+ break;
+
+ case SQL_ERROR:
+ auto record = records.get_status_record(1);
+ err_msg = record.get_message_text();
+ break;
+ }
+
+ // TODO: IGNITE-22226 Set a proper error here, not a standard one.
+ PyErr_SetString(PyExc_RuntimeError, err_msg.c_str());
+
+ return false;
+}
+
+
+
diff --git a/modules/platforms/python/cpp_module/py_connection.cpp
b/modules/platforms/python/cpp_module/py_connection.cpp
index 2dd6bd82b8..3960b17032 100644
--- a/modules/platforms/python/cpp_module/py_connection.cpp
+++ b/modules/platforms/python/cpp_module/py_connection.cpp
@@ -110,7 +110,11 @@ int prepare_py_connection_type() {
}
int register_py_connection_type(PyObject* mod) {
- return PyModule_AddObjectRef(mod, PY_CONNECTION_CLASS_NAME, (PyObject
*)&py_connection_type);
+ auto res = PyModule_AddObject(mod, PY_CONNECTION_CLASS_NAME, (PyObject
*)&py_connection_type);
+ if (res < 0) {
+ Py_DECREF((PyObject *)&py_connection_type);
+ }
+ return res;
}
py_connection *make_py_connection(std::unique_ptr<ignite::sql_environment> env,
diff --git a/modules/platforms/python/cpp_module/py_cursor.cpp
b/modules/platforms/python/cpp_module/py_cursor.cpp
index d3f76871d6..39a4961eb4 100644
--- a/modules/platforms/python/cpp_module/py_cursor.cpp
+++ b/modules/platforms/python/cpp_module/py_cursor.cpp
@@ -299,7 +299,11 @@ int prepare_py_cursor_type() {
}
int register_py_cursor_type(PyObject* mod) {
- return PyModule_AddObjectRef(mod, PY_CURSOR_CLASS_NAME, (PyObject
*)&py_cursor_type);
+ auto res = PyModule_AddObject(mod, PY_CURSOR_CLASS_NAME, (PyObject
*)&py_cursor_type);
+ if (res < 0) {
+ Py_DECREF((PyObject *)&py_cursor_type);
+ }
+ return res;
}
py_cursor *make_py_cursor(std::unique_ptr<ignite::sql_statement> stmt) {
diff --git a/modules/platforms/python/pyignite3/__init__.py
b/modules/platforms/python/pyignite3/__init__.py
index fabe96ac62..e4a77113d8 100644
--- a/modules/platforms/python/pyignite3/__init__.py
+++ b/modules/platforms/python/pyignite3/__init__.py
@@ -45,33 +45,34 @@ UUID = uuid.UUID
def type_code_from_int(native: int):
- match native:
- case native_type_code.NIL:
- return NIL
- case native_type_code.BOOLEAN:
- return BOOLEAN
- case native_type_code.INT8 | native_type_code.INT16 |
native_type_code.INT32 | native_type_code.INT64:
- return INT
- case native_type_code.FLOAT | native_type_code.DOUBLE:
- return FLOAT
- case native_type_code.DECIMAL | native_type_code.NUMBER:
- return NUMBER
- case native_type_code.DATE:
- return DATE
- case native_type_code.TIME:
- return TIME
- case native_type_code.DATETIME | native_type_code.TIMESTAMP:
- return DATETIME
- case native_type_code.UUID:
- return UUID
- case native_type_code.BITMASK:
- return INT
- case native_type_code.STRING:
- return STRING
- case native_type_code.BYTE_ARRAY:
- return BINARY
- case native_type_code.PERIOD | native_type_code.DURATION:
- return DATETIME
+ if native == native_type_code.NIL:
+ return NIL
+ elif native == native_type_code.BOOLEAN:
+ return BOOLEAN
+ elif (native == native_type_code.INT8 or native == native_type_code.INT16
+ or native == native_type_code.INT32 or native ==
native_type_code.INT64):
+ return INT
+ elif native == native_type_code.FLOAT or native == native_type_code.DOUBLE:
+ return FLOAT
+ elif native == native_type_code.DECIMAL or native ==
native_type_code.NUMBER:
+ return NUMBER
+ elif native == native_type_code.DATE:
+ return DATE
+ elif native == native_type_code.TIME:
+ return TIME
+ elif native == native_type_code.DATETIME or native ==
native_type_code.TIMESTAMP:
+ return DATETIME
+ elif native == native_type_code.UUID:
+ return UUID
+ elif native == native_type_code.BITMASK:
+ return INT
+ elif native == native_type_code.STRING:
+ return STRING
+ elif native == native_type_code.BYTE_ARRAY:
+ return BINARY
+ elif native == native_type_code.PERIOD or native ==
native_type_code.DURATION:
+ return DATETIME
+ raise InterfaceError(f'Unsupported data type: {native}')
class ColumnDescription:
diff --git a/modules/platforms/python/setup.py
b/modules/platforms/python/setup.py
index 9779d2e8b9..53628e5618 100644
--- a/modules/platforms/python/setup.py
+++ b/modules/platforms/python/setup.py
@@ -82,7 +82,7 @@ class CMakeBuild(build_ext):
for ext in self.extensions:
ext_dir =
os.path.abspath(os.path.dirname(self.get_ext_fullpath(ext.name)))
cfg = 'Release'
- ext_file =
os.path.splitext(self.get_ext_filename(self.get_ext_fullname(ext.name)))[0]
+ ext_file =
os.path.splitext(os.path.basename(self.get_ext_filename(ext.name)))[0]
cmake_args = [
f'-DCMAKE_BUILD_TYPE={cfg}',
diff --git a/modules/platforms/python/tox.ini b/modules/platforms/python/tox.ini
new file mode 100644
index 0000000000..542da4c479
--- /dev/null
+++ b/modules/platforms/python/tox.ini
@@ -0,0 +1,30 @@
+# 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.
+
+[tox]
+skipsdist = True
+envlist = codestyle,py{37,38,39}
+
+[testenv]
+passenv = TEAMCITY_VERSION IGNITE_HOME
+envdir = {homedir}/.virtualenvs/pyignite3-{envname}
+deps =
+ -r ./requirements/install.txt
+ -r ./requirements/tests.txt
+recreate = True
+usedevelop = True
+commands =
+ pytest {env:PYTESTARGS:} {posargs}
+