diff --git a/setup.py b/setup.py index 6480d78e7..08e4fa1e7 100644 --- a/setup.py +++ b/setup.py @@ -9,7 +9,7 @@ import shutil import subprocess -wip_version = "1.7.3" +wip_version = "1.8.0" def version_number(): """This function reads the version number which is populated by github actions""" diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index e50789232..75f7c2b8a 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -23,13 +23,8 @@ set(MARVEL_SOURCES "$<$:mvGraphics_linux.cpp>" # python - "mvPyObject.cpp" - "mvPythonTranslator.cpp" - "mvPythonParser.cpp" - "mvPythonExceptions.cpp" - "mvGlobalIntepreterLock.cpp" - "mvPythonTypeChecker.cpp" - "mvCustomTypes.cpp" + "mvPyUtils.cpp" + "mvCustomTypes.cpp" # ui "mvBasicWidgets.cpp" diff --git a/src/composite/mvFileDialog.cpp b/src/composite/mvFileDialog.cpp index 1d1d21032..62e25b462 100644 --- a/src/composite/mvFileDialog.cpp +++ b/src/composite/mvFileDialog.cpp @@ -1,7 +1,7 @@ #include "mvFileDialog.h" #include "mvFileExtension.h" #include "mvItemRegistry.h" -#include "mvPythonExceptions.h" +#include "mvPyUtils.h" #include "mvLog.h" static void Panel(const char* vFilter, IGFDUserDatas vUserDatas, bool* vCantContinue) diff --git a/src/composite/mvFileExtension.cpp b/src/composite/mvFileExtension.cpp index ade37c594..56a22ede0 100644 --- a/src/composite/mvFileExtension.cpp +++ b/src/composite/mvFileExtension.cpp @@ -1,7 +1,7 @@ #include "mvFileExtension.h" #include "mvFileDialog.h" #include "mvItemRegistry.h" -#include "mvPythonExceptions.h" +#include "mvPyUtils.h" #include "mvLog.h" void mvFileExtension::applySpecificTemplate(mvAppItem* item) diff --git a/src/custom/mvDatePicker.cpp b/src/custom/mvDatePicker.cpp index 6c7307c49..375e02891 100644 --- a/src/custom/mvDatePicker.cpp +++ b/src/custom/mvDatePicker.cpp @@ -4,7 +4,7 @@ #include #include #include "mvItemRegistry.h" -#include "mvPythonExceptions.h" +#include "mvPyUtils.h" #include "mvFontItems.h" #include "mvThemes.h" #include "mvContainers.h" diff --git a/src/custom/mvSlider3D.cpp b/src/custom/mvSlider3D.cpp index 650fad304..12f0fab43 100644 --- a/src/custom/mvSlider3D.cpp +++ b/src/custom/mvSlider3D.cpp @@ -1,5 +1,5 @@ #include "mvSlider3D.h" -#include "mvPythonExceptions.h" +#include "mvPyUtils.h" #include "mvFontItems.h" #include "mvThemes.h" #include "mvContainers.h" diff --git a/src/custom/mvTimePicker.cpp b/src/custom/mvTimePicker.cpp index 31ee8bbff..b8eebff52 100644 --- a/src/custom/mvTimePicker.cpp +++ b/src/custom/mvTimePicker.cpp @@ -4,7 +4,7 @@ #include #include "mvContext.h" #include "mvItemRegistry.h" -#include "mvPythonExceptions.h" +#include "mvPyUtils.h" #include "mvFontItems.h" #include "mvThemes.h" #include "mvContainers.h" diff --git a/src/dearpygui.cpp b/src/dearpygui.cpp index d1af240a4..322479b3d 100644 --- a/src/dearpygui.cpp +++ b/src/dearpygui.cpp @@ -6,12 +6,11 @@ #include #include "mvToolManager.h" #include "mvCustomTypes.h" -#include "mvPythonExceptions.h" +#include "mvPyUtils.h" #include "mvViewport.h" #include #include "mvLog.h" #include "mvProfiler.h" - #include "dearpygui_commands.h" #include "dearpygui_parsers.h" diff --git a/src/dearpygui.h b/src/dearpygui.h index d97398532..542b88e5a 100644 --- a/src/dearpygui.h +++ b/src/dearpygui.h @@ -2,10 +2,7 @@ #include #include -#include "mvPythonParser.h" - -#define PY_SSIZE_T_CLEAN -#include +#include "mvPyUtils.h" PyMODINIT_FUNC PyInit__dearpygui(void); diff --git a/src/dearpygui_commands.h b/src/dearpygui_commands.h index c90e04ae2..8cece262b 100644 --- a/src/dearpygui_commands.h +++ b/src/dearpygui_commands.h @@ -5,7 +5,7 @@ #include #include "mvToolManager.h" #include "mvCustomTypes.h" -#include "mvPythonExceptions.h" +#include "mvPyUtils.h" #include "mvViewport.h" #include "stb_image.h" #include "stb_image_write.h" diff --git a/src/dearpygui_parsers.h b/src/dearpygui_parsers.h index 294e824d8..35168cf9a 100644 --- a/src/dearpygui_parsers.h +++ b/src/dearpygui_parsers.h @@ -5,7 +5,7 @@ #include #include "mvToolManager.h" #include "mvCustomTypes.h" -#include "mvPythonExceptions.h" +#include "mvPyUtils.h" #include "mvViewport.h" #include #include "mvLog.h" diff --git a/src/mvAppItem.cpp b/src/mvAppItem.cpp index 061f75f95..32e000bd9 100644 --- a/src/mvAppItem.cpp +++ b/src/mvAppItem.cpp @@ -2,12 +2,9 @@ #include "mvContext.h" #include "mvItemRegistry.h" #include "mvCore.h" -#include "mvPythonExceptions.h" -#include "mvGlobalIntepreterLock.h" #include "mvAppItemCommons.h" #include "mvLog.h" -#include "mvPythonTypeChecker.h" -#include "mvPyObject.h" +#include "mvPyUtils.h" static void UpdateLocations(std::vector>* children, i32 slots) diff --git a/src/mvAppItem.h b/src/mvAppItem.h index 62db0c912..30d65dc77 100644 --- a/src/mvAppItem.h +++ b/src/mvAppItem.h @@ -13,7 +13,7 @@ #include #include "mvAppItemState.h" #include "mvCallbackRegistry.h" -#include "mvPythonTranslator.h" +#include "mvPyUtils.h" #include #include "mvAppItemTypes.inc" diff --git a/src/mvAppItemState.cpp b/src/mvAppItemState.cpp index 22ef73a69..a04ccf212 100644 --- a/src/mvAppItemState.cpp +++ b/src/mvAppItemState.cpp @@ -2,7 +2,7 @@ #include #include "mvAppItem.h" #include "mvContext.h" -#include "mvPyObject.h" +#include "mvPyUtils.h" void ResetAppItemState(mvAppItemState& state) diff --git a/src/mvBasicWidgets.cpp b/src/mvBasicWidgets.cpp index 99440fa9a..295f1fe8f 100644 --- a/src/mvBasicWidgets.cpp +++ b/src/mvBasicWidgets.cpp @@ -2,9 +2,8 @@ #include "mvFontItems.h" #include "mvThemes.h" #include "mvContainers.h" -#include "mvPyObject.h" +#include "mvPyUtils.h" #include "mvItemHandlers.h" -#include "mvPythonExceptions.h" #include #include "mvTextureItems.h" diff --git a/src/mvCallbackRegistry.cpp b/src/mvCallbackRegistry.cpp index 103d64805..e7502059a 100644 --- a/src/mvCallbackRegistry.cpp +++ b/src/mvCallbackRegistry.cpp @@ -5,9 +5,7 @@ #include #include "mvItemRegistry.h" #include "mvAppItemCommons.h" -#include "mvGlobalIntepreterLock.h" -#include "mvPythonExceptions.h" -#include "mvPyObject.h" +#include "mvPyUtils.h" void mvRunTasks() { diff --git a/src/mvColors.cpp b/src/mvColors.cpp index b590a32a0..c58ed010b 100644 --- a/src/mvColors.cpp +++ b/src/mvColors.cpp @@ -2,7 +2,7 @@ #include "mvContext.h" #include #include "mvItemRegistry.h" -#include "mvPythonExceptions.h" +#include "mvPyUtils.h" #include "mvFontItems.h" #include "mvThemes.h" #include "mvContainers.h" diff --git a/src/mvContainers.cpp b/src/mvContainers.cpp index 08efe393a..da01135b8 100644 --- a/src/mvContainers.cpp +++ b/src/mvContainers.cpp @@ -3,9 +3,8 @@ #include "mvFontItems.h" #include "mvThemes.h" #include "mvContainers.h" -#include "mvPyObject.h" +#include "mvPyUtils.h" #include "mvItemHandlers.h" -#include "mvPythonExceptions.h" #include #include "mvTextureItems.h" diff --git a/src/mvContext.cpp b/src/mvContext.cpp index b4c8c256a..7e7960566 100644 --- a/src/mvContext.cpp +++ b/src/mvContext.cpp @@ -9,9 +9,7 @@ #include #include "mvFontManager.h" #include "mvCallbackRegistry.h" -#include "mvPythonTranslator.h" -#include "mvPythonExceptions.h" -#include "mvGlobalIntepreterLock.h" +#include "mvPyUtils.h" #include #include "mvLog.h" #include "mvToolManager.h" diff --git a/src/mvContext.h b/src/mvContext.h index 2f3d7e96c..ea5c5101e 100644 --- a/src/mvContext.h +++ b/src/mvContext.h @@ -10,13 +10,10 @@ #include #include #include "mvCore.h" -#include "mvPythonParser.h" +#include "mvPyUtils.h" #include "mvTypes.h" #include "mvGraphics.h" -#define PY_SSIZE_T_CLEAN -#include - //----------------------------------------------------------------------------- // forward declarations //----------------------------------------------------------------------------- diff --git a/src/mvCustomTypes.cpp b/src/mvCustomTypes.cpp index 93ac647ee..7fde8116f 100644 --- a/src/mvCustomTypes.cpp +++ b/src/mvCustomTypes.cpp @@ -1,9 +1,7 @@ #include "mvCustomTypes.h" #include #include "mvTypes.h" -#include "mvPythonTranslator.h" -#include "mvPythonExceptions.h" -#include "mvPythonTypeChecker.h" +#include "mvPyUtils.h" static void intialize_mvMat4(mvMat4* a, diff --git a/src/mvDocWindow.cpp b/src/mvDocWindow.cpp index 97cab0488..a8928475f 100644 --- a/src/mvDocWindow.cpp +++ b/src/mvDocWindow.cpp @@ -1,5 +1,5 @@ #include -#include "mvPythonParser.h" +#include "mvPyUtils.h" #include "mvDocWindow.h" #include "dearpygui.h" diff --git a/src/mvDrawings.cpp b/src/mvDrawings.cpp index a01a19fb1..1007d8d96 100644 --- a/src/mvDrawings.cpp +++ b/src/mvDrawings.cpp @@ -1,7 +1,7 @@ #include "mvDrawings.h" #include "mvLog.h" #include "mvItemRegistry.h" -#include "mvPythonExceptions.h" +#include "mvPyUtils.h" #include "mvAppItemCommons.h" #include #include "mvContext.h" diff --git a/src/mvFontItems.cpp b/src/mvFontItems.cpp index 225ab7adf..d6e04d491 100644 --- a/src/mvFontItems.cpp +++ b/src/mvFontItems.cpp @@ -1,6 +1,6 @@ #include "mvFontItems.h" #include "mvTextureItems.h" -#include "mvPythonExceptions.h" +#include "mvPyUtils.h" #include "mvLog.h" #include "mvToolManager.h" #include "mvFontManager.h" diff --git a/src/mvFontManager.cpp b/src/mvFontManager.cpp index 9cb2c3f31..7ae7c11a6 100644 --- a/src/mvFontManager.cpp +++ b/src/mvFontManager.cpp @@ -8,7 +8,7 @@ #include "mvCore.h" #include "mvItemRegistry.h" #include "mvViewport.h" -#include "mvPythonExceptions.h" +#include "mvPyUtils.h" #include #include "mvTextureItems.h" #include diff --git a/src/mvGlobalHandlers.cpp b/src/mvGlobalHandlers.cpp index a83c73fe0..01cac20d7 100644 --- a/src/mvGlobalHandlers.cpp +++ b/src/mvGlobalHandlers.cpp @@ -1,5 +1,5 @@ #include "mvGlobalHandlers.h" -#include "mvPythonExceptions.h" +#include "mvPyUtils.h" #include "mvLog.h" #include "mvUtilities.h" diff --git a/src/mvGlobalIntepreterLock.cpp b/src/mvGlobalIntepreterLock.cpp deleted file mode 100644 index 9a92bbb6f..000000000 --- a/src/mvGlobalIntepreterLock.cpp +++ /dev/null @@ -1,15 +0,0 @@ -#include "mvGlobalIntepreterLock.h" -#include "mvContext.h" - -#define PY_SSIZE_T_CLEAN -#include - -mvGlobalIntepreterLock::mvGlobalIntepreterLock() -{ - _gstate = (int)PyGILState_Ensure(); -} - -mvGlobalIntepreterLock::~mvGlobalIntepreterLock() -{ - PyGILState_Release((PyGILState_STATE)_gstate); -} diff --git a/src/mvGlobalIntepreterLock.h b/src/mvGlobalIntepreterLock.h deleted file mode 100644 index 96ab829d4..000000000 --- a/src/mvGlobalIntepreterLock.h +++ /dev/null @@ -1,15 +0,0 @@ -#pragma once - -//----------------------------------------------------------------------------- -// mvGlobalIntepreterLock -// - A convience class to automatically handle aqcuiring and releasing -// python's global intpreter lock between python c api calls. -//----------------------------------------------------------------------------- -struct mvGlobalIntepreterLock -{ - int _gstate; - - mvGlobalIntepreterLock(); - ~mvGlobalIntepreterLock(); - -}; diff --git a/src/mvItemHandlers.cpp b/src/mvItemHandlers.cpp index 66f592d21..8ad21783e 100644 --- a/src/mvItemHandlers.cpp +++ b/src/mvItemHandlers.cpp @@ -1,5 +1,5 @@ #include "mvItemHandlers.h" -#include "mvPythonExceptions.h" +#include "mvPyUtils.h" #include "mvLog.h" void mvItemHandlerRegistry::checkEvents(void* data) diff --git a/src/mvItemRegistry.cpp b/src/mvItemRegistry.cpp index 9a668d91c..2a8b70fa5 100644 --- a/src/mvItemRegistry.cpp +++ b/src/mvItemRegistry.cpp @@ -1,16 +1,11 @@ #include "mvItemRegistry.h" #include "mvProfiler.h" #include "mvContext.h" -#include "mvItemRegistry.h" #include "mvAppItemCommons.h" #include "mvLog.h" -#include "mvPythonExceptions.h" -#include "mvToolManager.h" -#include "mvPythonExceptions.h" +#include "mvPyUtils.h" #include "mvToolManager.h" #include "mvFontManager.h" -#include "mvPythonTypeChecker.h" -#include "mvGlobalIntepreterLock.h" mvItemRegistry::mvItemRegistry() { diff --git a/src/mvItemRegistry.h b/src/mvItemRegistry.h index 261f13313..c6993cb2d 100644 --- a/src/mvItemRegistry.h +++ b/src/mvItemRegistry.h @@ -8,7 +8,7 @@ #include #include #include "mvAppItem.h" -#include "mvPyObject.h" +#include "mvPyUtils.h" //----------------------------------------------------------------------------- // forward declarations diff --git a/src/mvNodes.cpp b/src/mvNodes.cpp index 37423cebf..d69df6dfc 100644 --- a/src/mvNodes.cpp +++ b/src/mvNodes.cpp @@ -3,8 +3,7 @@ #include "mvContext.h" #include "mvItemRegistry.h" #include "mvLog.h" -#include "mvPythonExceptions.h" -#include "mvPyObject.h" +#include "mvPyUtils.h" #include "mvItemHandlers.h" #include "mvThemes.h" #include "mvContainers.h" diff --git a/src/mvPlotting.cpp b/src/mvPlotting.cpp index 44eb657a4..f078a4b03 100644 --- a/src/mvPlotting.cpp +++ b/src/mvPlotting.cpp @@ -3,11 +3,10 @@ #include "mvCore.h" #include "mvContext.h" #include "mvItemRegistry.h" -#include "mvPythonExceptions.h" +#include "mvPyUtils.h" #include "mvFontItems.h" #include "mvThemes.h" #include "mvContainers.h" -#include "mvPyObject.h" #include "mvTextureItems.h" #include "mvItemHandlers.h" diff --git a/src/mvPyObject.cpp b/src/mvPyObject.cpp deleted file mode 100644 index 4a0a1d99f..000000000 --- a/src/mvPyObject.cpp +++ /dev/null @@ -1,62 +0,0 @@ -#include "mvPyObject.h" -#include - -#define PY_SSIZE_T_CLEAN -#include - -mvPyObject::mvPyObject(PyObject* rawObject, bool borrowed) - : - m_rawObject(rawObject), - m_borrowed(borrowed), - m_ok(rawObject != nullptr) -{ - -} - -mvPyObject::mvPyObject(mvPyObject&& other) - : - m_rawObject(nullptr), - m_borrowed(false), - m_ok(false) -{ - std::swap(m_rawObject, other.m_rawObject); - std::swap(m_borrowed, other.m_borrowed); - std::swap(m_ok, other.m_ok); -} - -mvPyObject& mvPyObject::operator=(mvPyObject&& other) -{ - if (this != &other) - { - if (m_rawObject != nullptr && !m_borrowed) - Py_XDECREF(m_rawObject); - - std::swap(other.m_rawObject, m_rawObject); - std::swap(other.m_borrowed, m_borrowed); - std::swap(other.m_ok, m_ok); - } - - return *this; -} - -mvPyObject::~mvPyObject() -{ - if(!m_borrowed && !m_del) - Py_XDECREF(m_rawObject); -} - -mvPyObject::operator PyObject*() -{ - return m_rawObject; -} - -void mvPyObject::addRef() -{ - Py_XINCREF(m_rawObject); -} - -void mvPyObject::delRef() -{ - Py_XDECREF(m_rawObject); - m_del = true; -} \ No newline at end of file diff --git a/src/mvPyObject.h b/src/mvPyObject.h deleted file mode 100644 index f09b43f1c..000000000 --- a/src/mvPyObject.h +++ /dev/null @@ -1,38 +0,0 @@ -#pragma once - -// forward declare PyObject -// as suggested on the python mailing list -// http://mail.python.org/pipermail/python-dev/2003-August/037601.html -#ifndef PyObject_HEAD -struct _object; -typedef _object PyObject; -#endif - -class mvPyObject -{ - -public: - - mvPyObject(PyObject* rawObject, bool borrowed=false); - mvPyObject(mvPyObject&& other); - mvPyObject& operator=(mvPyObject&& other); - - mvPyObject(const mvPyObject& other) = delete; - mvPyObject& operator=(mvPyObject& other) = delete; - - ~mvPyObject(); - - void addRef(); - void delRef(); - bool isOk() const { return m_ok; } - - operator PyObject* (); - -private: - - PyObject* m_rawObject; - bool m_borrowed; - bool m_ok; - bool m_del = false; - -}; diff --git a/src/mvPyUtils.cpp b/src/mvPyUtils.cpp new file mode 100644 index 000000000..a33eecfe9 --- /dev/null +++ b/src/mvPyUtils.cpp @@ -0,0 +1,2938 @@ +#include "mvPyUtils.h" +#include + +#include +#include "mvAppItem.h" +#include "mvAppItemCommons.h" +#include "mvContext.h" +#include "mvItemRegistry.h" +#include "dearpygui.h" +#include +#include + +mvGlobalIntepreterLock::mvGlobalIntepreterLock() +{ + _gstate = (int)PyGILState_Ensure(); +} + +mvGlobalIntepreterLock::~mvGlobalIntepreterLock() +{ + PyGILState_Release((PyGILState_STATE)_gstate); +} + + +mvPyObject::mvPyObject(PyObject* rawObject, bool borrowed) + : + m_rawObject(rawObject), + m_borrowed(borrowed), + m_ok(rawObject != nullptr) +{ + +} + +mvPyObject::mvPyObject(mvPyObject&& other) + : + m_rawObject(nullptr), + m_borrowed(false), + m_ok(false) +{ + std::swap(m_rawObject, other.m_rawObject); + std::swap(m_borrowed, other.m_borrowed); + std::swap(m_ok, other.m_ok); +} + +mvPyObject& mvPyObject::operator=(mvPyObject&& other) +{ + if (this != &other) + { + if (m_rawObject != nullptr && !m_borrowed) + Py_XDECREF(m_rawObject); + + std::swap(other.m_rawObject, m_rawObject); + std::swap(other.m_borrowed, m_borrowed); + std::swap(other.m_ok, m_ok); + } + + return *this; +} + +mvPyObject::~mvPyObject() +{ + if(!m_borrowed && !m_del) + Py_XDECREF(m_rawObject); +} + +mvPyObject::operator PyObject*() +{ + return m_rawObject; +} + +void mvPyObject::addRef() +{ + Py_XINCREF(m_rawObject); +} + +void mvPyObject::delRef() +{ + Py_XDECREF(m_rawObject); + m_del = true; +} + +void +mvThrowPythonError(mvErrorCode code, const std::string& message) +{ + std::string fullMessage = "Error: [%d] Message: \t" + message; + PyErr_Format(PyExc_Exception, fullMessage.c_str(), (int)code); +} + +void +mvThrowPythonError(mvErrorCode code, const std::string& command, const std::string& message, mvAppItem* item) +{ + if (item) + { + std::string fullMessage = "\nError: [%d]\nCommand: %s\nItem: %d \nLabel: %s\nItem Type: %s\nMessage: %s"; + PyErr_Format(PyExc_Exception, + fullMessage.c_str(), + (int)code, + command.c_str(), + item->uuid, + item->config.specifiedLabel.c_str(), + DearPyGui::GetEntityTypeString(item->type), + message.c_str()); + } + else + { + std::string fullMessage = "\nError: [%d]\nCommand: %s\nItem: %d \nLabel: %s\nItem Type: %s\nMessage: %s"; + PyErr_Format(PyExc_Exception, + fullMessage.c_str(), + (int)code, + command.c_str(), + 0, + "Not found", + "Unknown", + message.c_str()); + } +} + +bool +isPyObject_Any(PyObject* obj) +{ + return obj != nullptr; +} + +bool +isPyObject_String(PyObject* obj) +{ + if (obj == nullptr) + return false; + + if (PyUnicode_Check(obj)) + return true; + else + { + PyObject* str = PyObject_Str(obj); + if (str == nullptr) + return false; + Py_XDECREF(str); + } + + return true; +} + +bool +isPyObject_Int(PyObject* obj) +{ + if (obj == nullptr) + return false; + + if (!PyNumber_Check(obj)) + return false; + return true; +} + +bool +isPyObject_Float(PyObject* obj) +{ + if (obj == nullptr) + return false; + + if (!PyNumber_Check(obj)) + return false; + return true; +} + +bool +isPyObject_Bool(PyObject* obj) +{ + if (obj == nullptr) + return false; + + if (!PyBool_Check(obj)) + return false; + return true; +} + +bool +isPyObject_StringList(PyObject* obj) +{ + if (obj == nullptr) + return false; + + if (PyTuple_Check(obj)) + { + if (PyTuple_Size(obj) > 1) + { + PyObject* item = PyTuple_GetItem(obj, 0); + if (PyUnicode_Check(item)) + return true; + else + return isPyObject_String(item); + } + + return true; + } + else if (PyList_Check(obj)) + { + if (PyList_Size(obj) > 1) + { + PyObject* item = PyList_GetItem(obj, 0); + if (PyUnicode_Check(item)) + return true; + else + return isPyObject_String(item); + } + + return true; + } + + return false; +} + +bool +isPyObject_ListStringList(PyObject* obj) +{ + if (obj == nullptr) + return false; + + if (PyTuple_Check(obj)) + { + if (PyTuple_Size(obj) > 1) + { + PyObject* item = PyTuple_GetItem(obj, 0); + return isPyObject_StringList(item); + } + + return true; + } + else if (PyList_Check(obj)) + { + if (PyList_Size(obj) > 1) + { + PyObject* item = PyList_GetItem(obj, 0); + return isPyObject_StringList(item); + } + + return true; + } + + return false; +} + +bool +isPyObject_FloatList(PyObject* obj) +{ + if (obj == nullptr) + return false; + + if (PyTuple_Check(obj)) + { + if (PyTuple_Size(obj) > 1) + { + PyObject* item = PyTuple_GetItem(obj, 0); + return isPyObject_Float(item); + } + + return true; + } + else if (PyList_Check(obj)) + { + if (PyList_Size(obj) > 1) + { + PyObject* item = PyList_GetItem(obj, 0); + return isPyObject_Float(item); + } + + return true; + } + + else if (PyObject_CheckBuffer(obj)) + { + return true; + } + + return false; +} + +bool +isPyObject_ListFloatList(PyObject* obj) +{ + if (obj == nullptr) + return false; + + if (PyTuple_Check(obj)) + { + if (PyTuple_Size(obj) > 1) + { + PyObject* item = PyTuple_GetItem(obj, 0); + return isPyObject_FloatList(item); + } + + return true; + } + else if (PyList_Check(obj)) + { + if (PyList_Size(obj) > 1) + { + PyObject* item = PyList_GetItem(obj, 0); + return isPyObject_FloatList(item); + } + + return true; + } + + return false; +} + +bool +isPyObject_IntList(PyObject* obj) +{ + if (obj == nullptr) + return false; + + if (PyTuple_Check(obj)) + { + if (PyTuple_Size(obj) > 1) + { + PyObject* item = PyTuple_GetItem(obj, 0); + return isPyObject_Int(item); + } + + return true; + } + else if (PyList_Check(obj)) + { + if (PyList_Size(obj) > 1) + { + PyObject* item = PyList_GetItem(obj, 0); + return isPyObject_Int(item); + } + + return true; + } + + else if (PyObject_CheckBuffer(obj)) + { + return true; + } + + return false; +} + +bool +isPyObject_ListIntList(PyObject* obj) +{ + if (obj == nullptr) + return false; + + if (PyTuple_Check(obj)) + { + if (PyTuple_Size(obj) > 1) + { + PyObject* item = PyTuple_GetItem(obj, 0); + return isPyObject_IntList(item); + } + + return true; + } + else if (PyList_Check(obj)) + { + if (PyList_Size(obj) > 1) + { + PyObject* item = PyList_GetItem(obj, 0); + return isPyObject_IntList(item); + } + + return true; + } + + return false; +} + +bool +isPyObject_Double(PyObject* obj) +{ + if (obj == nullptr) + return false; + + if (PyFloat_Check(obj)) + return true; + + return false; +} + +bool +isPyObject_Callable(PyObject* obj) +{ + if (obj == nullptr) + return false; + + if (PyCallable_Check(obj)) + return true; + return false; +} + +bool +isPyObject_Dict(PyObject* obj) +{ + if (obj == nullptr) + return false; + + if (PyDict_Check(obj)) + return true; + return false; +} + + +void +UpdatePyIntList(PyObject* pyvalue, const std::vector& value) +{ + if (pyvalue == nullptr) + return; + + + if (!PyList_Check(pyvalue)) + { + mvThrowPythonError(mvErrorCode::mvWrongType, "Python value error"); + return; + } + + + for (Py_ssize_t i = 0; i < PyList_Size(pyvalue); ++i) + { + if (static_cast(i) == value.size()) + break; + PyList_SetItem(pyvalue, i, PyLong_FromLong(value[i])); + } +} + +void +UpdatePyFloatList(PyObject* pyvalue, const std::vector& value) +{ + if (pyvalue == nullptr) + return; + + + if (!PyList_Check(pyvalue)) + { + mvThrowPythonError(mvErrorCode::mvWrongType, "Python value error"); + return; + } + + + for (Py_ssize_t i = 0; i < PyList_Size(pyvalue); ++i) + { + if (static_cast(i) == value.size()) + break; + PyList_SetItem(pyvalue, i, PyFloat_FromDouble(value[i])); + } +} + +void +UpdatePyStringStringList(PyObject* pyvalue, const std::vector>& value) +{ + if (pyvalue == nullptr) + return; + + + if (!PyList_Check(pyvalue)) + { + mvThrowPythonError(mvErrorCode::mvWrongType, "Python value error"); + return; + } + + + for (Py_ssize_t i = 0; i < PyList_Size(pyvalue); ++i) + { + if (static_cast(i) == value.size()) + break; + PyObject* row = PyList_GetItem(pyvalue, i); + for (Py_ssize_t j = 0; j < PyList_Size(row); ++j) + { + if (static_cast(j) == value[i].size()) + break; + PyList_SetItem(row, i, PyUnicode_FromString(value[i][j].c_str())); + } + } +} + +PyObject* +GetPyNone() +{ + Py_RETURN_NONE; +} + +PyObject* +ToPyString(const std::string& value) +{ + + return PyUnicode_FromString(value.c_str()); +} + +PyObject* +ToPyFloat(float value) +{ + + return PyFloat_FromDouble(value); +} + +PyObject* +ToPyDouble(double value) +{ + + return PyFloat_FromDouble(value); +} + +PyObject* +ToPyInt(int value) +{ + + return PyLong_FromLong(value); +} + +PyObject* +ToPyUUID(mvAppItem* item) +{ + + if (!item->config.alias.empty()) + return ToPyString(item->config.alias); + + return Py_BuildValue("K", item->uuid); +} + +PyObject* +ToPyUUID(mvUUID value) +{ + mvAppItem* item = GetItem(*GContext->itemRegistry, value); + if (item) + { + if (!item->config.alias.empty()) + return ToPyString(item->config.alias); + } + return Py_BuildValue("K", value); +} + +PyObject* +ToPyLong(long value) +{ + + return Py_BuildValue("K", value); +} + +PyObject* +ToPyBool(bool value) +{ + + return PyBool_FromLong(value); +} + +PyObject* +ToPyMPair(int x, float y) +{ + + return Py_BuildValue("[if]", x, y); +} + +PyObject* +ToPyMTrip(int i, float x, float y) +{ + + return Py_BuildValue("[iff]", i, x, y); +} + +PyObject* +ToPyPair(float x, float y) +{ + + return Py_BuildValue("[ff]", x, y); +} + +PyObject* +ToPyPairII(int x, int y) +{ + + return Py_BuildValue("[ii]", x, y); +} + +PyObject* +ToPyPair(double x, double y) +{ + + return Py_BuildValue("[dd]", x, y); +} + +PyObject* +ToPyPair(const std::string& x, const std::string& y) +{ + + return Py_BuildValue("[ss]", x.c_str(), y.c_str()); +} + +PyObject* +ToPyList(const std::vector& value) +{ + + + PyObject* result = PyList_New(value.size()); + + for (size_t i = 0; i < value.size(); ++i) + PyList_SetItem(result, i, PyLong_FromLong(value[i])); + + return result; +} + +PyObject* +ToPyList(const std::vector& value) +{ + + + PyObject* result = PyList_New(value.size()); + + for (size_t i = 0; i < value.size(); ++i) + PyList_SetItem(result, i, Py_BuildValue("K", value[i])); + + return result; +} + +PyObject* +ToPyList(const std::vector& value) +{ + + + PyObject* result = PyList_New(value.size()); + + for (size_t i = 0; i < value.size(); ++i) + { + PyObject* item = PyList_New(2); + PyList_SetItem(item, 0, PyFloat_FromDouble (value[i].x)); + PyList_SetItem(item, 1, PyFloat_FromDouble (value[i].y)); + PyList_SetItem(item, i, item); + } + + return result; +} + +PyObject* +ToPyList(const std::vector& value) +{ + + + PyObject* result = PyList_New(value.size()); + + for (size_t i = 0; i < value.size(); ++i) + { + PyObject* item = PyList_New(4); + PyList_SetItem(item, 0, PyFloat_FromDouble(value[i].x)); + PyList_SetItem(item, 1, PyFloat_FromDouble(value[i].y)); + PyList_SetItem(item, 2, PyFloat_FromDouble(value[i].z)); + PyList_SetItem(item, 3, PyFloat_FromDouble(value[i].w)); + PyList_SetItem(item, i, item); + } + + return result; +} + +PyObject* +ToPyList(const std::vector& value) +{ + + PyObject* result = PyList_New(value.size()); + + for (size_t i = 0; i < value.size(); ++i) + PyList_SetItem(result, i, PyFloat_FromDouble(value[i])); + + return result; +} + +PyObject* +ToPyList(const std::vector& value) +{ + + PyObject* result = PyList_New(value.size()); + + if(result) + { + for (size_t i = 0; i < value.size(); ++i) + PyList_SetItem(result, i, PyFloat_FromDouble(value[i])); + } + return result; +} + +PyObject* +ToPyList(const std::vector>& value) +{ + PyObject* result = PyList_New(value.size()); + + if(result) + { + for (size_t i = 0; i < value.size(); ++i) + PyList_SetItem(result, i, ToPyList(value[i])); + } + + return result; +} + +PyObject* +ToPyList(const std::vector>& value) +{ + PyObject* result = PyList_New(value.size()); + + if(result) + { + for (size_t i = 0; i < value.size(); ++i) + PyList_SetItem(result, i, ToPyList(value[i])); + } + + return result; +} + +PyObject* +ToPyList(const std::vector& value) +{ + + + PyObject* result = PyList_New(value.size()); + + for (size_t i = 0; i < value.size(); ++i) + PyList_SetItem(result, i, PyUnicode_FromString(value[i].c_str())); + + return result; +} + +PyObject* +ToPyList(const std::vector>& value) +{ + + + PyObject* result = PyList_New(value.size()); + + for (size_t i = 0; i < value.size(); ++i) + PyList_SetItem(result, i, ToPyList(value[i])); + + return result; +} + +PyObject* +ToPyList(const std::vector>& value) +{ + PyObject* result = PyList_New(value.size()); + + for (size_t i = 0; i < value.size(); ++i) + PyList_SetItem(result, i, ToPyPairII(value[i].first, value[i].second)); + + return result; +} + +PyObject* +ToPyList(const std::vector>& value) +{ + PyObject* result = PyList_New(value.size()); + + for (size_t i = 0; i < value.size(); ++i) + PyList_SetItem(result, i, ToPyPair(value[i].first, value[i].second)); + + return result; +} + +PyObject* +ToPyColor(const mvColor& color) +{ + + + PyObject* result = PyList_New(4); + + PyList_SetItem(result, 0, ToPyFloat((float)color.r)); + PyList_SetItem(result, 1, ToPyFloat((float)color.g)); + PyList_SetItem(result, 2, ToPyFloat((float)color.b)); + PyList_SetItem(result, 3, ToPyFloat((float)color.a)); + + return result; +} + +PyObject* +ToPyTime(const tm& time) +{ + + PyObject* dict = PyDict_New(); + PyDict_SetItemString(dict, "sec", mvPyObject(ToPyInt(time.tm_sec))); + PyDict_SetItemString(dict, "min", mvPyObject(ToPyInt(time.tm_min))); + PyDict_SetItemString(dict, "hour", mvPyObject(ToPyInt(time.tm_hour))); + PyDict_SetItemString(dict, "month_day", mvPyObject(ToPyInt(time.tm_mday))); + PyDict_SetItemString(dict, "month", mvPyObject(ToPyInt(time.tm_mon))); + PyDict_SetItemString(dict, "year", mvPyObject(ToPyInt(time.tm_year))); + PyDict_SetItemString(dict, "week_day", mvPyObject(ToPyInt(time.tm_wday))); + PyDict_SetItemString(dict, "year_day", mvPyObject(ToPyInt(time.tm_yday))); + PyDict_SetItemString(dict, "daylight_savings", mvPyObject(ToPyInt(time.tm_isdst))); + return dict; +} + +PyObject* +ToPyIntList(const int* value, int count) +{ + + + PyObject* result = PyList_New(count); + + for (int i = 0; i < count; ++i) + PyList_SetItem(result, i, PyLong_FromLong(value[i])); + + return result; +} + +PyObject* +ToPyFloatList(const float* value, int count) +{ + + + PyObject* result = PyList_New(count); + + for (int i = 0; i < count; ++i) + PyList_SetItem(result, i, PyFloat_FromDouble(value[i])); + + return result; +} + +PyObject* +ToPyFloatList(const double* value, int count) +{ + + + PyObject* result = PyList_New(count); + + for (int i = 0; i < count; ++i) + PyList_SetItem(result, i, PyFloat_FromDouble(value[i])); + + return result; +} + +tm +ToTime(PyObject* value, const std::string& message) +{ + tm result = {}; + if (value == nullptr) + return result; + + if (!PyDict_Check(value)) + { + mvThrowPythonError(mvErrorCode::mvWrongType, "Python value error. Must be dict/time."); + return result; + } + + if (PyObject* item = PyDict_GetItemString(value, "sec")) result.tm_sec = ToInt(item); + if (PyObject* item = PyDict_GetItemString(value, "min")) result.tm_min = ToInt(item); + if (PyObject* item = PyDict_GetItemString(value, "hour")) result.tm_hour = ToInt(item); + if (PyObject* item = PyDict_GetItemString(value, "month_day")) result.tm_mday = ToInt(item); + else result.tm_mday = 1; + if (PyObject* item = PyDict_GetItemString(value, "month")) result.tm_mon = ToInt(item); + if (PyObject* item = PyDict_GetItemString(value, "year")) result.tm_year = ToInt(item); + else result.tm_year = 70; + if (PyObject* item = PyDict_GetItemString(value, "week_day")) result.tm_wday = ToInt(item); + if (PyObject* item = PyDict_GetItemString(value, "year_day")) result.tm_yday = ToInt(item); + if (PyObject* item = PyDict_GetItemString(value, "daylight_savings")) result.tm_isdst = ToInt(item); + + return result; +} + +int +ToInt(PyObject* value, const std::string& message) +{ + if (value == nullptr) + return 0; + + + if (PyLong_Check(value)) + return PyLong_AsLong(value); + + else if (PyFloat_Check(value)) + return (int)PyFloat_AsDouble(value); + + mvThrowPythonError(mvErrorCode::mvWrongType, "Python value error. Must be int."); + return 0; +} + +mvUUID +ToUUID(PyObject* value, const std::string& message) +{ + if (value == nullptr) + return 0; + + if (PyUnicode_Check(value)) + { + std::string result = _PyUnicode_AsString(value); + mvUUID idfound = GetIdFromAlias(*GContext->itemRegistry, result); + if (idfound == 0) + { + mvThrowPythonError(mvErrorCode::mvWrongType, "UUID not found."); + return 0; + } + return idfound; + } + + if (!PyLong_Check(value)) + { + mvThrowPythonError(mvErrorCode::mvWrongType, "Python value error. Must be int."); + return 0; + } + + return PyLong_AsUnsignedLongLong(value); +} + +float +ToFloat(PyObject* value, const std::string& message) +{ + if (value == nullptr) + return 0.0f; + + + if (!PyNumber_Check(value)) + { + mvThrowPythonError(mvErrorCode::mvWrongType, "Python value error. Must be float."); + return 0.0f; + } + + if (PyLong_Check(value)) + { + return (float)PyLong_AsLong(value); + } + + return (float)PyFloat_AsDouble(value); +} + +double +ToDouble(PyObject* value, const std::string& message) +{ + if (value == nullptr) + return 0.0; + + + if (!PyNumber_Check(value)) + { + mvThrowPythonError(mvErrorCode::mvWrongType, "Python value error. Must be double."); + return 0.0; + } + + return PyFloat_AsDouble(value); +} + +bool +ToBool(PyObject* value, const std::string& message) +{ + if (value == nullptr) + return false; + + + if (!PyBool_Check(value)) + { + mvThrowPythonError(mvErrorCode::mvWrongType, "Python value error. Must be bool."); + return false; + } + + return PyLong_AsLong(value); +} + +std::string +ToString(PyObject* value, const std::string& message) +{ + std::string result; + if (value == nullptr) + return result; + + if (PyUnicode_Check(value)) + { + result = _PyUnicode_AsString(value); + } + else + { + PyObject* str = PyObject_Str(value); + if (str == nullptr) + { + mvThrowPythonError(mvErrorCode::mvWrongType, "Python value error. Must be string."); + return ""; + } + result = _PyUnicode_AsString(str); + Py_XDECREF(str); + } + + return result; + +} + +static std::function +BufferViewFunctionsFloat(Py_buffer& bufferView) +{ + if (strcmp(bufferView.format, "f") == 0) + return [](Py_buffer& bufferView, Py_ssize_t index) {return *((float*)bufferView.buf + index); }; + + else if (strcmp(bufferView.format, "d") == 0) + return [](Py_buffer& bufferView, Py_ssize_t index) {return (float)*((double*)bufferView.buf + index); }; + + else if (strcmp(bufferView.format, "i") == 0) + return [](Py_buffer& bufferView, Py_ssize_t index) {return (float)*((int*)bufferView.buf + index); }; + + else if (strcmp(bufferView.format, "I") == 0) + return [](Py_buffer& bufferView, Py_ssize_t index) {return (float)*((unsigned int*)bufferView.buf + index); }; + + else if (strcmp(bufferView.format, "l") == 0) + return [](Py_buffer& bufferView, Py_ssize_t index) {return (float)*((long*)bufferView.buf + index); }; + + else if (strcmp(bufferView.format, "L") == 0) + return [](Py_buffer& bufferView, Py_ssize_t index) {return (float)*((long long*)bufferView.buf + index); }; + + else if (strcmp(bufferView.format, "k") == 0) + return [](Py_buffer& bufferView, Py_ssize_t index) {return (float)*((unsigned long*)bufferView.buf + index); }; + + else if (strcmp(bufferView.format, "K") == 0) + return [](Py_buffer& bufferView, Py_ssize_t index) {return (float)*((unsigned long long*)bufferView.buf + index); }; + + else if (strcmp(bufferView.format, "B") == 0) + return [](Py_buffer& bufferView, Py_ssize_t index) {return (float)*((unsigned char*)bufferView.buf + index); }; + + else if (strcmp(bufferView.format, "b") == 0) + return [](Py_buffer& bufferView, Py_ssize_t index) {return (float)*((signed char*)bufferView.buf + index); }; + + else if (strcmp(bufferView.format, "c") == 0) + return [](Py_buffer& bufferView, Py_ssize_t index) {return (float)*((char*)bufferView.buf + index); }; + else + { + mvThrowPythonError(mvErrorCode::mvWrongType, "Unknown buffer type."); + mvThrowPythonError(mvErrorCode::mvWrongType, bufferView.format); + mvThrowPythonError(mvErrorCode::mvWrongType, "Currently supported buffer types f, d, l, B"); + return nullptr; + } +} + +static std::function +BufferViewFunctionsInt(Py_buffer& bufferView) +{ + if (strcmp(bufferView.format, "f") == 0) + return [](Py_buffer& bufferView, Py_ssize_t index) {return (int)*((float*)bufferView.buf + index); }; + + else if (strcmp(bufferView.format, "d") == 0) + return [](Py_buffer& bufferView, Py_ssize_t index) {return (int)*((double*)bufferView.buf + index); }; + + else if (strcmp(bufferView.format, "i") == 0) + return [](Py_buffer& bufferView, Py_ssize_t index) {return (int)*((int*)bufferView.buf + index); }; + + else if (strcmp(bufferView.format, "I") == 0) + return [](Py_buffer& bufferView, Py_ssize_t index) {return (int)*((unsigned int*)bufferView.buf + index); }; + + else if (strcmp(bufferView.format, "l") == 0) + return [](Py_buffer& bufferView, Py_ssize_t index) {return (int)*((long*)bufferView.buf + index); }; + + else if (strcmp(bufferView.format, "L") == 0) + return [](Py_buffer& bufferView, Py_ssize_t index) {return (int)*((long long*)bufferView.buf + index); }; + + else if (strcmp(bufferView.format, "k") == 0) + return [](Py_buffer& bufferView, Py_ssize_t index) {return (int)*((unsigned long*)bufferView.buf + index); }; + + else if (strcmp(bufferView.format, "K") == 0) + return [](Py_buffer& bufferView, Py_ssize_t index) {return (int)*((unsigned long long*)bufferView.buf + index); }; + + else if (strcmp(bufferView.format, "B") == 0) + return [](Py_buffer& bufferView, Py_ssize_t index) {return (int)*((unsigned char*)bufferView.buf + index); }; + + else if (strcmp(bufferView.format, "b") == 0) + return [](Py_buffer& bufferView, Py_ssize_t index) {return (int)*((signed char*)bufferView.buf + index); }; + + else if (strcmp(bufferView.format, "c") == 0) + return [](Py_buffer& bufferView, Py_ssize_t index) {return (int)*((char*)bufferView.buf + index); }; + else + { + mvThrowPythonError(mvErrorCode::mvWrongType, "Unknown buffer type."); + mvThrowPythonError(mvErrorCode::mvWrongType, bufferView.format); + mvThrowPythonError(mvErrorCode::mvWrongType, "Currently supported buffer types f, d, l, B"); + return nullptr; + } +} + +std::vector +ToUCharVect(PyObject* value, const std::string& message) +{ + std::vector items; + if (value == nullptr) + return items; + + if (PyTuple_Check(value)) + { + items.resize(PyTuple_Size(value)); + for (Py_ssize_t i = 0; i < PyTuple_Size(value); ++i) + { + items[i] = (unsigned char)PyLong_AsLong(PyTuple_GetItem(value, i)); + } + } + + else if (PyList_Check(value)) + { + items.resize(PyList_Size(value)); + for (Py_ssize_t i = 0; i < PyList_Size(value); ++i) + { + items[i] = (unsigned char)PyLong_AsLong(PyList_GetItem(value, i)); + } + } + + else if (PyObject_CheckBuffer(value)) + { + + + Py_buffer buffer_info; + + if (!PyObject_GetBuffer(value, &buffer_info, + PyBUF_CONTIG_RO | PyBUF_FORMAT)) + { + auto BufferViewer = BufferViewFunctionsInt(buffer_info); + + for (Py_ssize_t i = 0; i < buffer_info.len / buffer_info.itemsize; ++i) + { + items.emplace_back((unsigned char)BufferViewer(buffer_info, i)); + } + } + + PyBuffer_Release(&buffer_info); + } + + else + mvThrowPythonError(mvErrorCode::mvWrongType, "Python value error. Must be List[int]."); + + + return items; +} + +std::vector +ToIntVect(PyObject* value, const std::string& message) +{ + + std::vector items; + if (value == nullptr) + return items; + + if (PyTuple_Check(value)) + { + items.resize(PyTuple_Size(value)); + for (Py_ssize_t i = 0; i < PyTuple_Size(value); ++i) + { + items[i] = PyLong_AsLong(PyTuple_GetItem(value, i)); + } + } + + else if (PyList_Check(value)) + { + items.resize(PyList_Size(value)); + for (Py_ssize_t i = 0; i < PyList_Size(value); ++i) + { + items[i] = PyLong_AsLong(PyList_GetItem(value, i)); + } + } + + else if (PyObject_CheckBuffer(value)) + { + + + Py_buffer buffer_info; + + if (!PyObject_GetBuffer(value, &buffer_info, + PyBUF_CONTIG_RO | PyBUF_FORMAT)) + { + auto BufferViewer = BufferViewFunctionsInt(buffer_info); + + for (Py_ssize_t i = 0; i < buffer_info.len / buffer_info.itemsize; ++i) + { + items.emplace_back(BufferViewer(buffer_info, i)); + } + } + + PyBuffer_Release(&buffer_info); + } + + else + mvThrowPythonError(mvErrorCode::mvWrongType, "Python value error. Must be List[int]."); + + + return items; +} + +std::vector +ToUUIDVect(PyObject* value, const std::string& message) +{ + + std::vector items; + if (value == nullptr) + return items; + + + if (PyTuple_Check(value)) + { + items.resize(PyTuple_Size(value)); + for (Py_ssize_t i = 0; i < PyTuple_Size(value); ++i) + { + PyObject* item = PyTuple_GetItem(value, i); + if (isPyObject_Int(item)) + items[i] = PyLong_AsUnsignedLongLong(item); + else if (isPyObject_String(item)) + items[i] = GetIdFromAlias(*GContext->itemRegistry, ToString(item)); + } + } + + else if (PyList_Check(value)) + { + items.resize(PyList_Size(value)); + for (Py_ssize_t i = 0; i < PyList_Size(value); ++i) + { + PyObject* item = PyList_GetItem(value, i); + if (isPyObject_Int(item)) + items[i] = PyLong_AsUnsignedLongLong(item); + else if (isPyObject_String(item)) + items[i] = GetIdFromAlias(*GContext->itemRegistry, ToString(item)); + } + } + + else + mvThrowPythonError(mvErrorCode::mvWrongType, "Python value error. Must be List[int]."); + + + return items; +} + +std::vector +ToFloatVect(PyObject* value, const std::string& message) +{ + + std::vector items; + if (value == nullptr) + return items; + + + if (PyTuple_Check(value)) + { + for (Py_ssize_t i = 0; i < PyTuple_Size(value); ++i) + { + items.emplace_back((float)PyFloat_AsDouble(PyTuple_GetItem(value, i))); + } + } + + else if (PyList_Check(value)) + { + for (Py_ssize_t i = 0; i < PyList_Size(value); ++i) + { + items.emplace_back((float)PyFloat_AsDouble(PyList_GetItem(value, i))); + } + } + + else if (PyObject_CheckBuffer(value)) + { + Py_buffer buffer_info; + + if (!PyObject_GetBuffer(value, &buffer_info, + PyBUF_CONTIG_RO | PyBUF_FORMAT)) + { + + auto BufferViewer = BufferViewFunctionsFloat(buffer_info); + items.reserve(buffer_info.len / buffer_info.itemsize); + + for (Py_ssize_t i = 0; i < buffer_info.len / buffer_info.itemsize; ++i) + { + items.emplace_back(BufferViewer(buffer_info, i)); + } + } + PyBuffer_Release(&buffer_info); + } + + else + mvThrowPythonError(mvErrorCode::mvWrongType, "Python value error. Must be List[float]."); + + + return items; +} + +std::vector +ToDoubleVect(PyObject* value, const std::string& message) +{ + + std::vector items; + if (value == nullptr) + return items; + + + if (PyTuple_Check(value)) + { + for (Py_ssize_t i = 0; i < PyTuple_Size(value); ++i) + { + items.emplace_back(PyFloat_AsDouble(PyTuple_GetItem(value, i))); + } + } + + else if (PyList_Check(value)) + { + for (Py_ssize_t i = 0; i < PyList_Size(value); ++i) + { + items.emplace_back(PyFloat_AsDouble(PyList_GetItem(value, i))); + } + } + + else if (PyObject_CheckBuffer(value)) + { + Py_buffer buffer_info; + + if (!PyObject_GetBuffer(value, &buffer_info, + PyBUF_CONTIG_RO | PyBUF_FORMAT)) + { + + auto BufferViewer = BufferViewFunctionsFloat(buffer_info); + + for (Py_ssize_t i = 0; i < buffer_info.len / buffer_info.itemsize; ++i) + { + items.emplace_back(BufferViewer(buffer_info, i)); + } + } + PyBuffer_Release(&buffer_info); + } + + else + mvThrowPythonError(mvErrorCode::mvWrongType, "Python value error. Must be List[float]."); + + + return items; +} + +std::vector +ToStringVect(PyObject* value, const std::string& message) +{ + + std::vector items; + if (value == nullptr) + return items; + + + if (PyTuple_Check(value)) + { + for (Py_ssize_t i = 0; i < PyTuple_Size(value); ++i) + { + PyObject* item = PyTuple_GetItem(value, i); + if (PyUnicode_Check(item)) + items.emplace_back(_PyUnicode_AsString(item)); + else + { + PyObject* str = PyObject_Str(item); + items.emplace_back(_PyUnicode_AsString(str)); + Py_XDECREF(str); + } + } + } + + else if (PyList_Check(value)) + { + for (Py_ssize_t i = 0; i < PyList_Size(value); ++i) + { + PyObject* item = PyList_GetItem(value, i); + if (PyUnicode_Check(item)) + items.emplace_back(_PyUnicode_AsString(item)); + else + { + PyObject* str = PyObject_Str(item); + items.emplace_back(_PyUnicode_AsString(str)); + Py_XDECREF(str); + } + } + } + + else + mvThrowPythonError(mvErrorCode::mvWrongType, "Python value error. Must be List[str]."); + + + return items; +} + +mvColor +ToColor(PyObject* value, const std::string& message) +{ + float color[4] = { -1.0f, 0.0f, 0.0f, 1.0f }; + + if (value == nullptr) + return mvColor{ color[0], color[1], color[2], color[3] }; + + if (PyTuple_Check(value)) + { + for (Py_ssize_t i = 0; i < PyTuple_Size(value); ++i) + { + if (i >= 4) + break; + PyObject* item = PyTuple_GetItem(value, i); + if(PyNumber_Check(item)) + color[i] = (float)PyFloat_AsDouble(item)/255.0f; + } + + } + else if (PyList_Check(value)) + { + for (Py_ssize_t i = 0; i < PyList_Size(value); ++i) + { + if (i >= 4) + break; + PyObject* item = PyList_GetItem(value, i); + if (PyNumber_Check(item)) + color[i] = (float)PyFloat_AsDouble(item)/255.0f; + } + } + + return mvColor{ color[0], color[1], color[2], color[3] }; +} + +ImPlotPoint +ToPoint(PyObject* value, const std::string& message) +{ + if (value == nullptr) + return { 0.0, 0.0 }; + + std::vector result = ToDoubleVect(value, message); + + if (result.size() > 1) + return { result[0], result[1] }; + else if (result.size() == 1) + return { result[0], 0.0 }; + else + return { 0.0, 0.0 }; +} + +mvVec2 +ToVec2(PyObject* value, const std::string& message) +{ + if (value == nullptr) + return { 0.0f, 0.0f }; + + std::vector result = ToFloatVect(value, message); + + if (result.size() > 1) + return { result[0], result[1] }; + else if (result.size() == 1) + return { result[0], 0.0f }; + else + return { 0.0f, 0.0f }; +} + +mvVec4 +ToVec4(PyObject* value, const std::string& message) +{ + if (value == nullptr) + return { 0.0f, 0.0f, 0.0f, 0.0f }; + + std::vector result = ToFloatVect(value, message); + + if (result.size() > 3) + return { result[0], result[1], result[2], result[3] }; + else if (result.size() > 2) + return { result[0], result[1], result[2], 0.0f }; + else if (result.size() > 1) + return { result[0], result[1], 0.0f, 0.0f }; + else if (result.size() == 1) + return { result[0], 0.0f, 0.0f, 0.0f }; + else + return { 0.0f, 0.0f, 0.0f, 0.0f }; +} + +std::vector> +ToVectPairString(PyObject* value, const std::string& message) +{ + std::vector> items; + if (value == nullptr) + return items; + + + if (PyTuple_Check(value)) + { + for (Py_ssize_t i = 0; i < PyTuple_Size(value); ++i) + { + PyObject* item = PyTuple_GetItem(value, i); + if (PyTuple_Size(item) == 2) + items.emplace_back(PyUnicode_AsUTF8(PyTuple_GetItem(item, 0)), PyUnicode_AsUTF8(PyTuple_GetItem(item, 1))); + + } + + } + else if (PyList_Check(value)) + { + for (Py_ssize_t i = 0; i < PyList_Size(value); ++i) + { + PyObject* item = PyList_GetItem(value, i); + if (PyList_Size(item) == 2) + items.emplace_back(PyUnicode_AsUTF8(PyList_GetItem(item, 0)), PyUnicode_AsUTF8(PyList_GetItem(item, 1))); + + } + } + + else + mvThrowPythonError(mvErrorCode::mvWrongType, "Python value error. Must be List[List[str, str]]."); + + return items; +} + +std::vector +ToVectVec2(PyObject* value, const std::string& message) +{ + std::vector items; + if (value == nullptr) + return items; + + + if (PyTuple_Check(value)) + { + for (Py_ssize_t i = 0; i < PyTuple_Size(value); ++i) + items.push_back(ToVec2(PyTuple_GetItem(value, i))); + } + else if (PyList_Check(value)) + { + for (Py_ssize_t i = 0; i < PyList_Size(value); ++i) + items.push_back(ToVec2(PyList_GetItem(value, i))); + } + + else + mvThrowPythonError(mvErrorCode::mvWrongType, "Python value error. Must be List[List[int, int]]."); + + return items; +} + +std::pair, std::vector> +ToPairVec(PyObject* value, const std::string& message) +{ + std::pair, std::vector> items; + if (value == nullptr) + return items; + + + if (PyTuple_Check(value)) + { + if (PyTuple_Size(value) != 2) mvThrowPythonError(mvErrorCode::mvNone, message); + items.first = ToFloatVect(PyTuple_GetItem(value, 0), message); + items.second = ToFloatVect(PyTuple_GetItem(value, 1), message); + } + else if (PyList_Check(value)) + { + if (PyList_Size(value) != 2) mvThrowPythonError(mvErrorCode::mvNone, message); + items.first = ToFloatVect(PyList_GetItem(value, 0), message); + items.second = ToFloatVect(PyList_GetItem(value, 1), message); + } + + else + mvThrowPythonError(mvErrorCode::mvWrongType, message); + + return items; +} + +std::vector +ToVectVec4(PyObject* value, const std::string& message) +{ + std::vector items; + if (value == nullptr) + return items; + + + if (PyTuple_Check(value)) + { + for (Py_ssize_t i = 0; i < PyTuple_Size(value); ++i) + items.push_back(ToVec4(PyTuple_GetItem(value, i))); + } + else if (PyList_Check(value)) + { + for (Py_ssize_t i = 0; i < PyList_Size(value); ++i) + items.push_back(ToVec4(PyList_GetItem(value, i))); + } + + else + mvThrowPythonError(mvErrorCode::mvWrongType, message); + + return items; +} + +std::vector> +ToVectInt2(PyObject* value, const std::string& message) +{ + std::vector> items; + if (value == nullptr) + return items; + + + if (PyTuple_Check(value)) + { + for (Py_ssize_t i = 0; i < PyTuple_Size(value); ++i) + { + PyObject* point = PyTuple_GetItem(value, i); + if(PyTuple_Check(point)) + { + if (PyTuple_Size(point) >= 2) { + int x = PyLong_AsLong(PyTuple_GetItem(point, 0)); + int y = PyLong_AsLong(PyTuple_GetItem(point, 1)); + items.emplace_back(x, y); + } + } + else if(PyList_Check(point)) + { + if (PyList_Size(point) >= 2) { + int x = PyLong_AsLong(PyList_GetItem(point, 0)); + int y = PyLong_AsLong(PyList_GetItem(point, 1)); + items.emplace_back(x, y); + } + } + else + items.emplace_back(0, 0); + } + } + + else if (PyList_Check(value)) + { + for (Py_ssize_t i = 0; i < PyList_Size(value); ++i) + { + PyObject* point = PyList_GetItem(value, i); + if(PyTuple_Check(point)) + { + if (PyTuple_Size(point) >= 2) { + int x = PyLong_AsLong(PyTuple_GetItem(point, 0)); + int y = PyLong_AsLong(PyTuple_GetItem(point, 1)); + items.emplace_back(x, y); + } + } + else if(PyList_Check(point)) + { + if (PyList_Size(point) >= 2) { + int x = PyLong_AsLong(PyList_GetItem(point, 0)); + int y = PyLong_AsLong(PyList_GetItem(point, 1)); + items.emplace_back(x, y); + } + } + else + items.emplace_back(0, 0); + } + } + + else + mvThrowPythonError(mvErrorCode::mvWrongType, message); + + return items; + +} + +std::vector> +ToVectVectString(PyObject* value, const std::string& message) +{ + std::vector> items; + if (value == nullptr) + return items; + + + if (PyTuple_Check(value)) + { + for (Py_ssize_t i = 0; i < PyTuple_Size(value); ++i) + items.emplace_back(ToStringVect(PyTuple_GetItem(value, i), message)); + } + + else if (PyList_Check(value)) + { + for (Py_ssize_t i = 0; i < PyList_Size(value); ++i) + items.emplace_back(ToStringVect(PyList_GetItem(value, i), message)); + } + + return items; +} + +std::vector> +ToVectPairStringFloat(PyObject* value, const std::string& message) +{ + std::vector> items; + if (value == nullptr) + return items; + + + if (PyTuple_Check(value)) + { + for (Py_ssize_t i = 0; i < PyTuple_Size(value); ++i) + { + PyObject* item = PyTuple_GetItem(value, i); + if (PyTuple_Size(item) == 2 && PyNumber_Check(PyTuple_GetItem(item, 1))) + items.emplace_back(PyUnicode_AsUTF8(PyTuple_GetItem(item, 0)), (float)PyFloat_AsDouble(PyTuple_GetItem(item, 1))); + + } + + } + else if (PyList_Check(value)) + { + for (Py_ssize_t i = 0; i < PyList_Size(value); ++i) + { + PyObject* item = PyList_GetItem(value, i); + if (PyList_Size(item) == 2 && PyNumber_Check(PyList_GetItem(item, 1))) + items.emplace_back(PyUnicode_AsUTF8(PyList_GetItem(item, 0)), (float)PyFloat_AsDouble(PyList_GetItem(item, 1))); + + } + } + + else + mvThrowPythonError(mvErrorCode::mvWrongType, message); + + return items; +} + +std::vector> +ToVectVectFloat(PyObject* value, const std::string& message) +{ + std::vector> items; + if (value == nullptr) + return items; + + + if (PyTuple_Check(value)) + { + for (Py_ssize_t i = 0; i < PyTuple_Size(value); ++i) + items.emplace_back(ToFloatVect(PyTuple_GetItem(value, i), message)); + } + + else if (PyList_Check(value)) + { + for (Py_ssize_t i = 0; i < PyList_Size(value); ++i) + items.emplace_back(ToFloatVect(PyList_GetItem(value, i), message)); + } + + return items; +} + +std::vector> +ToVectVectInt(PyObject* value, const std::string& message) +{ + std::vector> items; + if (value == nullptr) + return items; + + + if (PyTuple_Check(value)) + { + for (Py_ssize_t i = 0; i < PyTuple_Size(value); ++i) + items.emplace_back(ToIntVect(PyTuple_GetItem(value, i), message)); + } + + else if (PyList_Check(value)) + { + for (Py_ssize_t i = 0; i < PyList_Size(value); ++i) + items.emplace_back(ToIntVect(PyList_GetItem(value, i), message)); + } + + return items; +} + +std::vector> +ToVectVectDouble(PyObject* value, const std::string& message) +{ + std::vector> items; + if (value == nullptr) + return items; + + + if (PyTuple_Check(value)) + { + for (Py_ssize_t i = 0; i < PyTuple_Size(value); ++i) + items.emplace_back(ToDoubleVect(PyTuple_GetItem(value, i), message)); + } + + else if (PyList_Check(value)) + { + for (Py_ssize_t i = 0; i < PyList_Size(value); ++i) + items.emplace_back(ToDoubleVect(PyList_GetItem(value, i), message)); + } + + return items; +} + + + +static bool +VerifyArguments(int start, PyObject* args, const std::vector& elements) +{ + + if (start >= PyTuple_Size(args)) + return true; + + int end = (int)PyTuple_Size(args); + if (end > (int)elements.size()) + end = (int)elements.size(); + + for (int i = start; i < end; i++) + { + const auto& item = elements[i]; + PyObject* obj = nullptr; + obj = PyTuple_GetItem(args, i); + + switch (item.type) + { + case mvPyDataType::String: + if (!isPyObject_String(obj)) + return false; + break; + + case mvPyDataType::UUID: + { + if (isPyObject_Int(obj)) + break; + else if (isPyObject_String(obj)) + break; + return false; + } + + case mvPyDataType::Long: + case mvPyDataType::Integer: + if (!isPyObject_Int(obj)) + return false; + break; + + case mvPyDataType::Float: + if (!isPyObject_Float(obj)) + return false; + break; + + case mvPyDataType::Bool: + if (!isPyObject_Bool(obj)) + return false; + break; + + case mvPyDataType::StringList: + if (!isPyObject_StringList(obj)) + return false; + break; + + case mvPyDataType::FloatList: + if (!isPyObject_FloatList(obj)) + return false; + break; + + case mvPyDataType::IntList: + if (!isPyObject_IntList(obj)) + return false; + break; + + case mvPyDataType::Double: + if (!isPyObject_Double(obj)) + return false; + break; + + case mvPyDataType::Callable: + if (!isPyObject_Callable(obj)) + return false; + break; + + case mvPyDataType::Dict: + if (!isPyObject_Dict(obj)) + return false; + break; + + case mvPyDataType::ListFloatList: + if (!isPyObject_ListFloatList(obj)) + return false; + break; + + case mvPyDataType::ListStrList: + if (!isPyObject_ListStringList(obj)) + return false; + break; + + case mvPyDataType::ListListInt: + if (!isPyObject_ListIntList(obj)) + return false; + break; + + default: + if (!isPyObject_Any(obj)) + return false; + } + } + + return true; +} + +static char +PythonDataTypeSymbol(mvPyDataType type) +{ + switch (type) + { + //case mvPyDataType::UUID: return 'K'; + case mvPyDataType::Long: return 'l'; + case mvPyDataType::String: return 's'; + case mvPyDataType::Integer: return 'i'; + case mvPyDataType::Float: return 'f'; + case mvPyDataType::Double: return 'd'; + case mvPyDataType::Bool: return 'p'; + default: return 'O'; + } +} + +static const char* +PythonDataTypeString(mvPyDataType type) +{ + switch (type) + { + case mvPyDataType::String: return " : str"; + case mvPyDataType::UUID: return " : Union[int, str]"; + case mvPyDataType::Integer: return " : int"; + case mvPyDataType::Long: return " : int"; + case mvPyDataType::Float: return " : float"; + case mvPyDataType::Double: return " : float"; + case mvPyDataType::Bool: return " : bool"; + case mvPyDataType::StringList: return " : Union[List[str], Tuple[str, ...]]"; + case mvPyDataType::FloatList: return " : Union[List[float], Tuple[float, ...]]"; + case mvPyDataType::DoubleList: return " : Union[List[float], Tuple[float, ...]]"; + case mvPyDataType::IntList: return " : Union[List[int], Tuple[int, ...]]"; + case mvPyDataType::UUIDList: return " : Union[List[int], Tuple[int, ...]]"; + case mvPyDataType::Callable: return " : Callable"; + case mvPyDataType::Dict: return " : dict"; + case mvPyDataType::ListAny: return " : List[Any]"; + case mvPyDataType::ListListInt: return " : List[Union[List[int], Tuple[int, ...]]]"; + case mvPyDataType::ListFloatList: return " : List[List[float]]"; + case mvPyDataType::ListDoubleList: return " : List[List[float]]"; + case mvPyDataType::ListStrList: return " : List[List[str]]"; + case mvPyDataType::Object: return " : Any"; + default: return " : unknown"; + } +} + +const char* +PythonDataTypeActual(mvPyDataType type) +{ + switch (type) + { + case mvPyDataType::String: return "str"; + case mvPyDataType::UUID: return "Union[int, str]"; + case mvPyDataType::Integer: return "int"; + case mvPyDataType::Long: return "int"; + case mvPyDataType::Float: return "float"; + case mvPyDataType::Double: return "float"; + case mvPyDataType::Bool: return "bool"; + case mvPyDataType::StringList: return "Union[List[str], Tuple[str, ...]]"; + case mvPyDataType::FloatList: return "Union[List[float], Tuple[float, ...]]"; + case mvPyDataType::IntList: return "Union[List[int], Tuple[int, ...]]"; + case mvPyDataType::UUIDList: return "Union[List[int], Tuple[int, ...]]"; + case mvPyDataType::Callable: return "Callable"; + case mvPyDataType::Dict: return "dict"; + case mvPyDataType::ListFloatList: return "List[List[float]]"; + case mvPyDataType::ListStrList: return "List[List[str]]"; + case mvPyDataType::None: return "None"; + case mvPyDataType::Object: return "Any"; + default: return "Any"; + } +} + +mvPythonParser +FinalizeParser(const mvPythonParserSetup& setup, const std::vector& args) +{ + + mvPythonParser parser; + + // separate args into category + for (auto& arg : args) + { + switch (arg.arg_type) + { + case mvArgType::REQUIRED_ARG: + parser.required_elements.push_back(arg); + break; + case mvArgType::POSITIONAL_ARG: + parser.optional_elements.push_back(arg); + break; + case mvArgType::KEYWORD_ARG: + parser.keyword_elements.push_back(arg); + break; + default: + parser.deprecated_elements.push_back(arg); + } + } + + // build format string and keywords + if (!parser.required_elements.empty()) + { + for (auto& element : parser.required_elements) + { + parser.formatstring.push_back(PythonDataTypeSymbol(element.type)); + parser.keywords.push_back(element.name); + } + } + + parser.formatstring.push_back('|'); + + if (!parser.optional_elements.empty()) + { + + for (auto& element : parser.optional_elements) + { + parser.formatstring.push_back(PythonDataTypeSymbol(element.type)); + parser.keywords.push_back(element.name); + } + } + + if (!parser.keyword_elements.empty()) + { + parser.formatstring.push_back('$'); + for (auto& element : parser.keyword_elements) + { + parser.formatstring.push_back(PythonDataTypeSymbol(element.type)); + parser.keywords.push_back(element.name); + } + } + parser.formatstring.push_back(0); + parser.keywords.push_back(NULL); + + parser.about = setup.about; + parser.returnType = setup.returnType; + parser.category = setup.category; + parser.createContextManager = setup.createContextManager; + parser.unspecifiedKwargs = setup.unspecifiedKwargs; + parser.internal = setup.internal; + + // build documentation + std::string documentation = parser.about + "\n\nReturn Type: " + PythonDataTypeActual(parser.returnType) + "\n"; + + if (!parser.required_elements.empty()) + documentation += "\n\nRequired Arguments\n_______________\n\n"; + + for (const auto& element : parser.required_elements) + { + documentation += "\n* "; + documentation += element.name + std::string(PythonDataTypeString(element.type)); + documentation += "\n\t\t" + std::string(element.description); + } + + if (!parser.optional_elements.empty()) + documentation += "\n\nOptional Arguments\n_______________\n\n"; + + for (const auto& element : parser.optional_elements) + { + documentation += "\n* "; + documentation += element.name + std::string(PythonDataTypeString(element.type)); + documentation += " = " + std::string(element.default_value); + documentation += "\n\t\t" + std::string(element.description); + } + + if (!parser.keyword_elements.empty()) + documentation += "\n\nKeyword Arguments\n_______________\n\n"; + + for (const auto& element : parser.keyword_elements) + { + documentation += "\n* "; + documentation += element.name + std::string(PythonDataTypeString(element.type)); + documentation += " = " + std::string(element.default_value); + documentation += "\n\t\t" + std::string(element.description); + } + + if (!parser.keyword_elements.empty()) + documentation += "\n\nDeprecated Keyword Arguments\n_______________\n\n"; + + for (const auto& element : parser.deprecated_elements) + { + documentation += "\n* "; + documentation += element.name + std::string(PythonDataTypeString(element.type)); + documentation += " = " + std::string(element.default_value); + documentation += "\n\t\t" + std::string(element.description); + } + + parser.documentation = std::move(documentation); + + return parser; +} + +bool +VerifyRequiredArguments(const mvPythonParser& parser, PyObject* args) +{ + + // ensure enough args were provided + if ((size_t)PyTuple_Size(args) < parser.required_elements.size()) + { + assert(false && "Not enough arguments provided"); + mvThrowPythonError(mvErrorCode::mvNone, "Not enough arguments provided. Expected: " + + std::to_string(parser.required_elements.size()) + " Recieved: " + std::to_string((size_t)PyTuple_Size(args))); + return false; + } + + return VerifyArguments(0, args, parser.required_elements); +} + +bool +VerifyPositionalArguments(const mvPythonParser& parser, PyObject* args) +{ + return VerifyArguments((int)parser.optional_elements.size(), args, parser.optional_elements); +} + +bool +VerifyKeywordArguments(const mvPythonParser& parser, PyObject* args) +{ + if (args == nullptr) + return false; + + if (!PyArg_ValidateKeywordArguments(args)) + return false; + + PyObject* keys = PyDict_Keys(args); + + bool exists = false; + for (int i = 0; i < PyList_Size(keys); i++) + { + PyObject* item = PyList_GetItem(keys, i); + auto sitem = ToString(item); + + bool found = false; + for (const auto& keyword : parser.keyword_elements) + { + if (sitem == keyword.name) + { + found = true; + break; + } + } + + if (found) + continue; + else + { + for (const auto& keyword : parser.optional_elements) + { + if (sitem == keyword.name) + { + found = true; + break; + } + } + + if (found) + continue; + } + + for (const auto& keyword : parser.required_elements) + { + if (sitem == keyword.name) + { + found = true; + break; + } + } + + if (found) + continue; + + for (const auto& keyword : parser.deprecated_elements) + { + if (sitem == keyword.name) + { + found = true; + break; + } + } + + if (found) + continue; + + mvThrowPythonError(mvErrorCode::mvNone, sitem + " keyword does not exist."); + assert(false); + exists = false; + break; + } + + Py_XDECREF(keys); + + return exists; +} + +bool +VerifyArgumentCount(const mvPythonParser& parser, PyObject* args) +{ + if (args == nullptr && parser.required_elements.size() == 0) + return true; + if (args == nullptr) + { + mvThrowPythonError(mvErrorCode::mvNone, "This command has a minimum number of arguments of " + std::to_string(parser.required_elements.size())); + return false; + } + + int possibleArgs = (int)parser.required_elements.size() + (int)parser.optional_elements.size(); + int minArgs = (int)parser.required_elements.size(); + int numberOfArgs = (int)PyTuple_Size(args); + + if (numberOfArgs > possibleArgs) + { + mvThrowPythonError(mvErrorCode::mvNone, "This command has a maximum number of arguments of " + std::to_string(possibleArgs) + + " but recieved " + std::to_string(numberOfArgs)); + return false; + } + if (numberOfArgs < minArgs) + { + mvThrowPythonError(mvErrorCode::mvNone, "This command has a minimum number of arguments of " + std::to_string(minArgs) + + " but only recieved " + std::to_string(numberOfArgs)); + return false; + } + return true; +} + +bool +Parse(const mvPythonParser& parser, PyObject* args, PyObject* kwargs, const char* message, ...) +{ + + bool check = true; + + va_list arguments; + va_start(arguments, message); + if (!PyArg_VaParseTupleAndKeywords(args, kwargs, parser.formatstring.data(), + const_cast(parser.keywords.data()), arguments)) + { + check = false; + } + + va_end(arguments); + + if (!check) + mvThrowPythonError(mvErrorCode::mvNone, "Error parsing Dear PyGui command: " + std::string(message)); + + return check; +} + +void +GenerateStubFile(const std::string& directory) +{ + const auto& commands = GetModuleParsers(); + + std::ofstream stub; + stub.open(directory + "/_dearpygui.pyi"); + + stub << "from typing import List, Any, Callable, Union, Tuple\n"; + stub << "from dearpygui._dearpygui import *\n\n"; + stub << "##########################################################\n"; + stub << "# This file is generated automatically by mvPythonParser #\n"; + stub << "##########################################################\n\n"; + stub << "# ~ Dear PyGui Version: " << MV_SANDBOX_VERSION << "\n"; + + for (const auto& parser : commands) + { + stub << "def " << parser.first << "("; + + bool first_arg = true; + for (const auto& args : parser.second.required_elements) + { + if (first_arg) + first_arg = false; + else + stub << ", "; + stub << args.name << PythonDataTypeString(args.type); + } + + for (const auto& args : parser.second.optional_elements) + { + if (first_arg) + first_arg = false; + else + stub << ", "; + stub << args.name << PythonDataTypeString(args.type) << " =''"; + } + + if (!parser.second.keyword_elements.empty()) + { + if (first_arg) + first_arg = false; + else + stub << ", "; + + stub << "*"; + } + + for (const auto& args : parser.second.keyword_elements) + stub << ", " << args.name << ": " << PythonDataTypeActual(args.type) << " =''"; + + if (parser.second.unspecifiedKwargs) + stub << ", **kwargs"; + + stub << ") -> " << PythonDataTypeActual(parser.second.returnType) << ":"; + + stub << "\n\t\"\"\"" << parser.second.about.c_str() << "\"\"\""; + + stub << "\n\t...\n\n"; + } + + auto& constants = GetModuleConstants(); + + for (auto& item : constants) + stub << item.first << "=0\n"; + + stub.close(); +} + +void +GenerateCoreFile(std::ofstream& stream) +{ + const auto& commands = GetModuleParsers(); + + // current date/time based on current system + time_t now = time(0); + + // convert now to string form + char* dt = ctime(&now); + + for (const auto& parser : commands) + { + if (parser.second.internal) + continue; + + stream << "def " << parser.first << "("; + + bool first_arg = true; + for (const auto& args : parser.second.required_elements) + { + if (first_arg) + first_arg = false; + else + stream << ", "; + stream << args.name << PythonDataTypeString(args.type); + } + + for (const auto& args : parser.second.optional_elements) + { + if (first_arg) + first_arg = false; + else + stream << ", "; + stream << args.name << PythonDataTypeString(args.type) << " =" << args.default_value; + } + + if (!parser.second.keyword_elements.empty()) + { + if (first_arg) + first_arg = false; + else + stream << ", "; + + stream << "*"; + } + + for (const auto& args : parser.second.keyword_elements) + stream << ", " << args.name << ": " << PythonDataTypeActual(args.type) << " =" << args.default_value; + + if (first_arg) + stream << "**kwargs) -> "; + else + stream << ", **kwargs) -> "; + stream << PythonDataTypeActual(parser.second.returnType) << ":"; + + stream << "\n\t\"\"\"\t " << parser.second.about.c_str(); + + stream << "\n\n\tArgs:"; + for (const auto& args : parser.second.required_elements) + { + stream << "\n\t\t" << args.name << " (" << PythonDataTypeActual(args.type) << "): " << args.description; + } + + for (const auto& args : parser.second.optional_elements) + { + stream << "\n\t\t" << args.name << " (" << PythonDataTypeActual(args.type) << ", optional): " << args.description; + } + + for (const auto& args : parser.second.keyword_elements) + { + stream << "\n\t\t" << args.name << " (" << PythonDataTypeActual(args.type) << ", optional): " << args.description; + } + + for (const auto& args : parser.second.deprecated_elements) + { + stream << "\n\t\t" << args.name << " (" << PythonDataTypeActual(args.type) << ", optional): (deprecated) " << args.description; + } + + stream << "\n\tReturns:"; + stream << "\n\t\t" << PythonDataTypeActual(parser.second.returnType); + stream << "\n\t\"\"\""; + + + for (const auto& args : parser.second.deprecated_elements) + { + if (args.arg_type == mvArgType::DEPRECATED_REMOVE_KEYWORD_ARG) + { + stream << "\n\n\tif '" << args.name << "' in kwargs.keys():"; + stream << "\n\n\t\twarnings.warn('" << args.name << " keyword removed', DeprecationWarning, 2)"; + stream << "\n\n\t\tkwargs.pop('" << args.name << "', None)"; + } + + else if (args.arg_type == mvArgType::DEPRECATED_RENAME_KEYWORD_ARG) + { + stream << "\n\n\tif '" << args.name << "' in kwargs.keys():"; + stream << "\n\t\twarnings.warn('" << args.name << " keyword renamed to " << args.new_name << "', DeprecationWarning, 2)"; + stream << "\n\t\t" << args.new_name << "=kwargs['" << args.name << "']"; + } + } + + stream << "\n\n\treturn internal_dpg." << parser.first << "("; + + first_arg = true; + for (const auto& args : parser.second.required_elements) + { + if (first_arg) + first_arg = false; + else + stream << ", "; + stream << args.name; + } + + for (const auto& args : parser.second.optional_elements) + { + if (first_arg) + first_arg = false; + else + stream << ", "; + stream << args.name; + } + + for (const auto& args : parser.second.keyword_elements) + { + if (first_arg) + first_arg = false; + else + stream << ", "; + stream << args.name << "=" << args.name; + } + + if (first_arg) + stream << "**kwargs)\n\n"; + else + stream << ", **kwargs)\n\n"; + } +} + +void +GenerateContextsFile(std::ofstream& stream) +{ + const auto& commands = GetModuleParsers(); + + // current date/time based on current system + time_t now = time(0); + + // convert now to string form + char* dt = ctime(&now); + + for (const auto& parser : commands) + { + if (!parser.second.createContextManager) + continue; + + stream << "\n@contextmanager\n"; + stream << "def " << parser.first.substr(4) << "("; + + bool first_arg = true; + for (const auto& args : parser.second.required_elements) + { + if (first_arg) + first_arg = false; + else + stream << ", "; + stream << args.name << PythonDataTypeString(args.type); + } + + for (const auto& args : parser.second.optional_elements) + { + if (first_arg) + first_arg = false; + else + stream << ", "; + stream << args.name << PythonDataTypeString(args.type) << " =" << args.default_value; + } + + if (!parser.second.keyword_elements.empty()) + { + if (first_arg) + first_arg = false; + else + stream << ", "; + + stream << "*"; + } + + for (const auto& args : parser.second.keyword_elements) + stream << ", " << args.name << ": " << PythonDataTypeActual(args.type) << " =" << args.default_value; + + if (first_arg) + stream << "**kwargs) -> "; + else + stream << ", **kwargs) -> "; + stream << PythonDataTypeActual(parser.second.returnType) << ":"; + + stream << "\n\t\"\"\"\t " << parser.second.about.c_str(); + + stream << "\n\n\tArgs:"; + for (const auto& args : parser.second.required_elements) + { + stream << "\n\t\t" << args.name << " (" << PythonDataTypeActual(args.type) << "): " << args.description; + } + + for (const auto& args : parser.second.optional_elements) + { + stream << "\n\t\t" << args.name << " (" << PythonDataTypeActual(args.type) << ", optional): " << args.description; + } + + for (const auto& args : parser.second.keyword_elements) + { + stream << "\n\t\t" << args.name << " (" << PythonDataTypeActual(args.type) << ", optional): " << args.description; + } + + for (const auto& args : parser.second.deprecated_elements) + { + stream << "\n\t\t" << args.name << " (" << PythonDataTypeActual(args.type) << ", optional): (deprecated) " << args.description; + } + + stream << "\n\tYields:"; + stream << "\n\t\t" << PythonDataTypeActual(parser.second.returnType); + stream << "\n\t\"\"\""; + + stream << "\n\ttry:"; + + for (const auto& args : parser.second.deprecated_elements) + { + if (args.arg_type == mvArgType::DEPRECATED_REMOVE_KEYWORD_ARG) + { + stream << "\n\n\t\tif '" << args.name << "' in kwargs.keys():"; + stream << "\n\t\t\twarnings.warn('" << args.name << " keyword removed', DeprecationWarning, 2)"; + stream << "\n\t\t\tkwargs.pop('" << args.name << "', None)"; + } + + else if (args.arg_type == mvArgType::DEPRECATED_RENAME_KEYWORD_ARG) + { + stream << "\n\n\t\tif '" << args.name << "' in kwargs.keys():"; + stream << "\n\t\t\twarnings.warn('" << args.name << " keyword renamed to " << args.new_name << "', DeprecationWarning, 2)"; + stream << "\n\t\t\t" << args.new_name << "=kwargs['" << args.name << "']"; + } + } + + stream << "\n\t\twidget = internal_dpg." << parser.first << "("; + + first_arg = true; + for (const auto& args : parser.second.required_elements) + { + if (first_arg) + first_arg = false; + else + stream << ", "; + stream << args.name; + } + + for (const auto& args : parser.second.optional_elements) + { + if (first_arg) + first_arg = false; + else + stream << ", "; + stream << args.name; + } + + for (const auto& args : parser.second.keyword_elements) + { + if (first_arg) + first_arg = false; + else + stream << ", "; + stream << args.name << "=" << args.name; + } + + if (first_arg) + stream << "**kwargs)\n"; + else + stream << ", **kwargs)\n"; + + stream << "\t\tinternal_dpg.push_container_stack(widget)\n"; + stream << "\t\tyield widget\n"; + stream << "\tfinally:\n"; + stream << "\t\tinternal_dpg.pop_container_stack()\n"; + + } + +} + +void +GenerateCoreFileRTD(std::ofstream& stream) +{ + const auto& commands = GetModuleParsers(); + + // current date/time based on current system + time_t now = time(0); + + // convert now to string form + char* dt = ctime(&now); + + for (const auto& parser : commands) + { + if (parser.second.internal) + continue; + + stream << "def " << parser.first << "("; + + bool first_arg = true; + for (const auto& args : parser.second.required_elements) + { + if (first_arg) + first_arg = false; + else + stream << ", "; + stream << args.name; + } + + for (const auto& args : parser.second.optional_elements) + { + if (first_arg) + first_arg = false; + else + stream << ", "; + stream << args.name << "=" << args.default_value; + } + + if (parser.second.keyword_elements.empty()) + stream << "):"; + else + { + if(parser.second.required_elements.empty() && parser.second.optional_elements.empty()) + stream << "**kwargs):"; + else + stream << ", **kwargs):"; + } + + stream << "\n\t\"\"\"\t " << parser.second.about.c_str(); + + stream << "\n\n\tArgs:"; + for (const auto& args : parser.second.required_elements) + { + stream << "\n\t\t" << args.name << " (" << PythonDataTypeActual(args.type) << "): " << args.description; + } + + for (const auto& args : parser.second.optional_elements) + { + stream << "\n\t\t" << args.name << " (" << PythonDataTypeActual(args.type) << ", optional): " << args.description; + } + + for (const auto& args : parser.second.keyword_elements) + { + stream << "\n\t\t" << args.name << " (" << PythonDataTypeActual(args.type) << ", optional): " << args.description; + } + + for (const auto& args : parser.second.deprecated_elements) + { + stream << "\n\t\t" << args.name << " (" << PythonDataTypeActual(args.type) << ", optional): (deprecated)" << args.description; + } + + stream << "\n\tReturns:"; + stream << "\n\t\t" << PythonDataTypeActual(parser.second.returnType); + stream << "\n\t\"\"\""; + + stream << "\n\n\treturn internal_dpg." << parser.first << "("; + + first_arg = true; + for (const auto& args : parser.second.required_elements) + { + if (first_arg) + first_arg = false; + else + stream << ", "; + stream << args.name; + } + + for (const auto& args : parser.second.optional_elements) + { + if (first_arg) + first_arg = false; + else + stream << ", "; + stream << args.name; + } + + if (!parser.second.keyword_elements.empty()) + { + if (parser.second.required_elements.empty() && parser.second.optional_elements.empty()) + stream << "**kwargs"; + else + stream << ", **kwargs"; + } + + stream << ")\n\n"; + } +} + +void +GenerateContextsFileRTD(std::ofstream& stream) +{ + const auto& commands = GetModuleParsers(); + + // current date/time based on current system + time_t now = time(0); + + // convert now to string form + char* dt = ctime(&now); + + for (const auto& parser : commands) + { + if (!parser.second.createContextManager) + continue; + + stream << "\n@contextmanager\n"; + stream << "def " << parser.first.substr(4) << "("; + + bool first_arg = true; + for (const auto& args : parser.second.required_elements) + { + if (first_arg) + first_arg = false; + else + stream << ", "; + stream << args.name; + } + + for (const auto& args : parser.second.optional_elements) + { + if (first_arg) + first_arg = false; + else + stream << ", "; + stream << args.name << "=" << args.default_value; + } + + if (parser.second.keyword_elements.empty()) + stream << "):"; + else + { + if (parser.second.required_elements.empty() && parser.second.optional_elements.empty()) + stream << "**kwargs):"; + else + stream << ", **kwargs):"; + } + + stream << "\n\t\"\"\"\t " << parser.second.about.c_str(); + + stream << "\n\n\tArgs:"; + for (const auto& args : parser.second.required_elements) + { + stream << "\n\t\t" << args.name << " (" << PythonDataTypeActual(args.type) << "): " << args.description; + } + + for (const auto& args : parser.second.optional_elements) + { + stream << "\n\t\t" << args.name << " (" << PythonDataTypeActual(args.type) << ", optional): " << args.description; + } + + for (const auto& args : parser.second.keyword_elements) + { + stream << "\n\t\t" << args.name << " (" << PythonDataTypeActual(args.type) << ", optional): " << args.description; + } + + for (const auto& args : parser.second.deprecated_elements) + { + stream << "\n\t\t" << args.name << " (" << PythonDataTypeActual(args.type) << ", optional): (deprecated)" << args.description; + } + + stream << "\n\tYields:"; + stream << "\n\t\t" << PythonDataTypeActual(parser.second.returnType); + stream << "\n\t\"\"\""; + + stream << "\n\ttry:"; + stream << "\n\t\twidget = internal_dpg." << parser.first << "("; + + first_arg = true; + for (const auto& args : parser.second.required_elements) + { + if (first_arg) + first_arg = false; + else + stream << ", "; + stream << args.name; + } + + for (const auto& args : parser.second.optional_elements) + { + if (first_arg) + first_arg = false; + else + stream << ", "; + stream << args.name; + } + + if (!parser.second.keyword_elements.empty()) + { + if (parser.second.required_elements.empty() && parser.second.optional_elements.empty()) + stream << "**kwargs"; + else + stream << ", **kwargs"; + } + + stream << ")\n"; + stream << "\t\tinternal_dpg.push_container_stack(widget)\n"; + stream << "\t\tyield widget\n"; + stream << "\tfinally:\n"; + stream << "\t\tinternal_dpg.pop_container_stack()\n"; + + } + +} + +void +GenerateDearPyGuiFile(const std::string& directory) +{ + std::ofstream stub; + stub.open(directory + "/dearpygui.py"); + + stub << "\n##########################################################\n"; + stub << "# Dear PyGui User Interface\n"; + stub << "# ~ Version: " << MV_SANDBOX_VERSION << "\n"; + stub << "#\n"; + stub << "# Notes:\n"; + stub << "# * This file is automatically generated.\n#\n"; + stub << "# Resources:\n"; + stub << "# * FAQ: https://github.com/hoffstadt/DearPyGui/discussions/categories/frequently-asked-questions-faq \n"; + stub << "# * Homepage: https://github.com/hoffstadt/DearPyGui \n"; + stub << "# * Wiki: https://github.com/hoffstadt/DearPyGui/wiki \n"; + stub << "# * Issues: https://github.com/hoffstadt/DearPyGui/issues\n"; + stub << "# * Discussions: https://github.com/hoffstadt/DearPyGui/discussions\n"; + stub << "##########################################################\n\n"; + + std::ifstream inputStream0(directory + "/_header.py"); + + for (std::string line; std::getline(inputStream0, line);) + stub << line << "\n"; + + stub << "\n##########################################################\n"; + stub << "# Deprecated Commands\n"; + stub << "##########################################################\n"; + + std::ifstream inputStream1(directory + "/_deprecated.py"); + + for (std::string line; std::getline(inputStream1, line);) + stub << line << "\n"; + + stub << "\n##########################################################\n"; + stub << "# Container Context Managers\n"; + stub << "##########################################################\n\n"; + + GenerateContextsFile(stub); + + stub << "\n##########################################################\n"; + stub << "# Core Wrappings\n"; + stub << "##########################################################\n\n"; + + GenerateCoreFile(stub); + + stub << "\n##########################################################\n"; + stub << "# Constants #\n"; + stub << "##########################################################\n\n"; + + auto& constants = GetModuleConstants(); + + for (auto& item : constants) + stub << item.first << "=internal_dpg." << item.first << "\n"; + + stub.close(); + + std::ofstream redirect; + redirect.open(directory + "/_dearpygui.py"); + redirect << "from _dearpygui import *\n"; + redirect.close(); +} + +void +GenerateDearPyGuiFileRTD(const std::string& directory) +{ + std::ofstream stub; + stub.open(directory + "/_dearpygui_RTD.py"); + + stub << "\n##########################################################\n"; + stub << "# Dear PyGui User Interface (MODIFIED FOR READTHEDOCS)\n"; + stub << "# ~ Version: " << MV_SANDBOX_VERSION << "\n"; + stub << "#\n"; + stub << "# Notes:\n"; + stub << "# * This file is automatically generated.\n#\n"; + stub << "# Resources:\n"; + stub << "# * FAQ: https://github.com/hoffstadt/DearPyGui/discussions/categories/frequently-asked-questions-faq \n"; + stub << "# * Homepage: https://github.com/hoffstadt/DearPyGui \n"; + stub << "# * Wiki: https://github.com/hoffstadt/DearPyGui/wiki \n"; + stub << "# * Issues: https://github.com/hoffstadt/DearPyGui/issues\n"; + stub << "# * Discussions: https://github.com/hoffstadt/DearPyGui/discussions\n"; + stub << "##########################################################\n\n"; + + std::ifstream inputStream0(directory + "/_header.py"); + + for (std::string line; std::getline(inputStream0, line);) + stub << line << "\n"; + + stub << "\n##########################################################\n"; + stub << "# Deprecated Commands\n"; + stub << "##########################################################\n"; + + std::ifstream inputStream1(directory + "/_deprecated.py"); + + for (std::string line; std::getline(inputStream1, line);) + stub << line << "\n"; + + stub << "\n##########################################################\n"; + stub << "# Container Context Managers\n"; + stub << "##########################################################\n\n"; + + GenerateContextsFileRTD(stub); + + stub << "\n##########################################################\n"; + stub << "# Core Wrappings\n"; + stub << "##########################################################\n\n"; + + GenerateCoreFileRTD(stub); + + stub << "\n##########################################################\n"; + stub << "# Constants #\n"; + stub << "##########################################################\n\n"; + + auto& constants = GetModuleConstants(); + + for (auto& item : constants) + stub << item.first << "=internal_dpg." << item.first << "\n"; + + stub.close(); + + std::ofstream redirect; + redirect.open(directory + "/_dearpygui.py"); + redirect << "from _dearpygui import *\n"; + redirect.close(); +} + +void +AddCommonArgs(std::vector& args, CommonParserArgs argsFlags) +{ + + args.push_back({ mvPyDataType::UUID, "id", mvArgType::DEPRECATED_RENAME_KEYWORD_ARG, "0", "", "tag" }); + args.push_back({ mvPyDataType::String, "label", mvArgType::KEYWORD_ARG, "None", "Overrides 'name' as label." }); + args.push_back({ mvPyDataType::Object, "user_data", mvArgType::KEYWORD_ARG, "None", "User data for callbacks" }); + args.push_back({ mvPyDataType::Bool, "use_internal_label", mvArgType::KEYWORD_ARG, "True", "Use generated internal label instead of user specified (appends ### uuid)." }); + + if (argsFlags & MV_PARSER_ARG_ID) args.push_back({ mvPyDataType::UUID, "tag", mvArgType::KEYWORD_ARG, "0", "Unique id used to programmatically refer to the item.If label is unused this will be the label." }); + if (argsFlags & MV_PARSER_ARG_WIDTH) args.push_back({ mvPyDataType::Integer, "width", mvArgType::KEYWORD_ARG, "0", "Width of the item." }); + if (argsFlags & MV_PARSER_ARG_HEIGHT) args.push_back({ mvPyDataType::Integer, "height", mvArgType::KEYWORD_ARG, "0", "Height of the item." }); + if (argsFlags & MV_PARSER_ARG_INDENT) args.push_back({ mvPyDataType::Integer, "indent", mvArgType::KEYWORD_ARG, "-1", "Offsets the widget to the right the specified number multiplied by the indent style." }); + if (argsFlags & MV_PARSER_ARG_PARENT) args.push_back({ mvPyDataType::UUID, "parent", mvArgType::KEYWORD_ARG, "0", "Parent to add this item to. (runtime adding)" }); + if (argsFlags & MV_PARSER_ARG_BEFORE) args.push_back({ mvPyDataType::UUID, "before", mvArgType::KEYWORD_ARG, "0", "This item will be displayed before the specified item in the parent." }); + if (argsFlags & MV_PARSER_ARG_SOURCE) args.push_back({ mvPyDataType::UUID, "source", mvArgType::KEYWORD_ARG, "0", "Overrides 'id' as value storage key." }); + if (argsFlags & MV_PARSER_ARG_PAYLOAD_TYPE) args.push_back({ mvPyDataType::String, "payload_type", mvArgType::KEYWORD_ARG, "'$$DPG_PAYLOAD'", "Sender string type must be the same as the target for the target to run the payload_callback." }); + if (argsFlags & MV_PARSER_ARG_CALLBACK) args.push_back({ mvPyDataType::Callable, "callback", mvArgType::KEYWORD_ARG, "None", "Registers a callback." }); + if (argsFlags & MV_PARSER_ARG_DRAG_CALLBACK)args.push_back({ mvPyDataType::Callable, "drag_callback", mvArgType::KEYWORD_ARG, "None", "Registers a drag callback for drag and drop." }); + if (argsFlags & MV_PARSER_ARG_DROP_CALLBACK)args.push_back({ mvPyDataType::Callable, "drop_callback", mvArgType::KEYWORD_ARG, "None", "Registers a drop callback for drag and drop." }); + if (argsFlags & MV_PARSER_ARG_SHOW) args.push_back({ mvPyDataType::Bool, "show", mvArgType::KEYWORD_ARG, "True", "Attempt to render widget." }); + if (argsFlags & MV_PARSER_ARG_ENABLED) args.push_back({ mvPyDataType::Bool, "enabled", mvArgType::KEYWORD_ARG, "True", "Turns off functionality of widget and applies the disabled theme." }); + if (argsFlags & MV_PARSER_ARG_POS) args.push_back({ mvPyDataType::IntList, "pos", mvArgType::KEYWORD_ARG, "[]", "Places the item relative to window coordinates, [0,0] is top left." }); + if (argsFlags & MV_PARSER_ARG_FILTER) args.push_back({ mvPyDataType::String, "filter_key", mvArgType::KEYWORD_ARG, "''", "Used by filter widget." }); + if (argsFlags & MV_PARSER_ARG_SEARCH_DELAY) args.push_back({ mvPyDataType::Bool, "delay_search", mvArgType::KEYWORD_ARG, "False", "Delays searching container for specified items until the end of the app. Possible optimization when a container has many children that are not accessed often." }); + + if (argsFlags & MV_PARSER_ARG_TRACKED) + { + args.push_back({ mvPyDataType::Bool, "tracked", mvArgType::KEYWORD_ARG, "False", "Scroll tracking" }); + args.push_back({ mvPyDataType::Float, "track_offset", mvArgType::KEYWORD_ARG, "0.5", "0.0f:top, 0.5f:center, 1.0f:bottom" }); + } + +} \ No newline at end of file diff --git a/src/mvPythonTranslator.h b/src/mvPyUtils.h similarity index 51% rename from src/mvPythonTranslator.h rename to src/mvPyUtils.h index 0ccfa7dc7..d3bc93ecd 100644 --- a/src/mvPythonTranslator.h +++ b/src/mvPyUtils.h @@ -1,32 +1,93 @@ #pragma once -//----------------------------------------------------------------------------- -// mvPythonTranslator -// -// - These functions handle conversion between python/c++ types while also -// ensuring thread safety on the python interpreter -// -// - Needs rework badly -// -//----------------------------------------------------------------------------- - #include #include #include #include #include +#include +#include +#include #include "mvCore.h" -// forward declare PyObject -// as suggested on the python mailing list -// http://mail.python.org/pipermail/python-dev/2003-August/037601.html -#ifndef PyObject_HEAD -struct _object; -typedef _object PyObject; -#endif +#define PY_SSIZE_T_CLEAN +#include +// forward declarations class mvAppItem; +struct mvGlobalIntepreterLock +{ + int _gstate; + + mvGlobalIntepreterLock(); + ~mvGlobalIntepreterLock(); + +}; + +class mvPyObject +{ + +public: + + mvPyObject(PyObject* rawObject, bool borrowed=false); + mvPyObject(mvPyObject&& other); + mvPyObject& operator=(mvPyObject&& other); + + mvPyObject(const mvPyObject& other) = delete; + mvPyObject& operator=(mvPyObject& other) = delete; + + ~mvPyObject(); + + void addRef(); + void delRef(); + bool isOk() const { return m_ok; } + + operator PyObject* (); + +private: + + PyObject* m_rawObject; + bool m_borrowed; + bool m_ok; + bool m_del = false; + +}; + +enum class mvErrorCode +{ + mvNone = 1000, + mvTextureNotFound = 1001, + mvIncompatibleType = 1002, + mvIncompatibleParent = 1003, + mvIncompatibleChild = 1004, + mvItemNotFound = 1005, + mvSourceNotFound = 1006, + mvSourceNotCompatible = 1007, + mvWrongType = 1008, + mvContainerStackEmpty = 1009, + mvStagingModeOff = 1010, + mvParentNotDeduced = 1011, +}; + +void mvThrowPythonError(mvErrorCode code, const std::string& message); +void mvThrowPythonError(mvErrorCode code, const std::string& command, const std::string& message, mvAppItem* item); + +bool isPyObject_String (PyObject* obj); +bool isPyObject_Int (PyObject* obj); +bool isPyObject_Float (PyObject* obj); +bool isPyObject_Bool (PyObject* obj); +bool isPyObject_StringList (PyObject* obj); +bool isPyObject_ListStringList(PyObject* obj); +bool isPyObject_FloatList (PyObject* obj); +bool isPyObject_ListFloatList (PyObject* obj); +bool isPyObject_IntList (PyObject* obj); +bool isPyObject_ListIntList (PyObject* obj); +bool isPyObject_Double (PyObject* obj); +bool isPyObject_Callable (PyObject* obj); +bool isPyObject_Dict (PyObject* obj); +bool isPyObject_Any (PyObject* obj); + // conversion to python PyObject* GetPyNone (); PyObject* ToPyUUID (mvAppItem* item); @@ -95,4 +156,97 @@ std::vector> ToVectVectString (PyObject* std::vector> ToVectVectFloat (PyObject* value, const std::string& message = "Type must be an list/tuple of list/tuple of floats."); std::vector> ToVectVectInt (PyObject* value, const std::string& message = "Type must be an list/tuple of list/tuple of ints."); std::vector> ToVectVectDouble (PyObject* value, const std::string& message = "Type must be an list/tuple of list/tuple of doubles."); -std::vector> ToVectPairStringFloat(PyObject* value, const std::string& message = "Type must be an list/tuple of str,float pairs."); \ No newline at end of file +std::vector> ToVectPairStringFloat(PyObject* value, const std::string& message = "Type must be an list/tuple of str,float pairs."); + +enum class mvPyDataType +{ + None = 0, + Integer, Float, Double, String, Bool, Object, Callable, Dict, + IntList, FloatList, DoubleList, StringList, ListAny, + ListListInt, ListFloatList, ListDoubleList, ListStrList, UUID, + UUIDList, Long, + Any +}; + +enum class mvArgType +{ + REQUIRED_ARG = 0, + POSITIONAL_ARG, + KEYWORD_ARG, + DEPRECATED_RENAME_KEYWORD_ARG, + DEPRECATED_REMOVE_KEYWORD_ARG +}; + +enum CommonParserArgs +{ + MV_PARSER_ARG_ID = 1 << 1, + MV_PARSER_ARG_WIDTH = 1 << 2, + MV_PARSER_ARG_HEIGHT = 1 << 3, + MV_PARSER_ARG_INDENT = 1 << 4, + MV_PARSER_ARG_PARENT = 1 << 5, + MV_PARSER_ARG_BEFORE = 1 << 6, + MV_PARSER_ARG_SOURCE = 1 << 7, + MV_PARSER_ARG_CALLBACK = 1 << 8, + MV_PARSER_ARG_SHOW = 1 << 9, + MV_PARSER_ARG_ENABLED = 1 << 10, + MV_PARSER_ARG_POS = 1 << 11, + MV_PARSER_ARG_DROP_CALLBACK = 1 << 12, + MV_PARSER_ARG_DRAG_CALLBACK = 1 << 13, + MV_PARSER_ARG_PAYLOAD_TYPE = 1 << 14, + MV_PARSER_ARG_TRACKED = 1 << 15, + MV_PARSER_ARG_FILTER = 1 << 16, + MV_PARSER_ARG_SEARCH_DELAY = 1 << 17 +}; + +struct mvPythonDataElement +{ + mvPyDataType type = mvPyDataType::None; + const char* name = ""; + mvArgType arg_type = mvArgType::REQUIRED_ARG; + const char* default_value = "..."; + const char* description = ""; + const char* new_name = ""; +}; + +struct mvPythonParser +{ + std::vector required_elements; + std::vector optional_elements; + std::vector keyword_elements; + std::vector deprecated_elements; + std::vector formatstring; + std::vector keywords; + std::string documentation; + bool unspecifiedKwargs = false; + bool createContextManager = false; + bool internal = false; + std::string about; + mvPyDataType returnType = mvPyDataType::None; + std::vector category; +}; + +struct mvPythonParserSetup +{ + std::string about = "Undocumented"; + mvPyDataType returnType = mvPyDataType::None; + std::vector category = {"General"}; + bool createContextManager = false; + bool unspecifiedKwargs = false; + bool internal = false; +}; + +mvPythonParser FinalizeParser(const mvPythonParserSetup& setup, const std::vector& args); +bool Parse(const mvPythonParser& parser, PyObject* args, PyObject* kwargs, const char* message, ...); +const char* PythonDataTypeActual(mvPyDataType type); +void AddCommonArgs(std::vector& args, CommonParserArgs argsFlags); + +// arguments checks +bool VerifyRequiredArguments (const mvPythonParser& parser, PyObject* args); +bool VerifyPositionalArguments(const mvPythonParser& parser, PyObject* args); +bool VerifyKeywordArguments (const mvPythonParser& parser, PyObject* args); +bool VerifyArgumentCount (const mvPythonParser& parser, PyObject* args); + +// file generation +void GenerateStubFile (const std::string& directory); +void GenerateDearPyGuiFile (const std::string& directory); +void GenerateDearPyGuiFileRTD(const std::string& directory); diff --git a/src/mvPythonExceptions.cpp b/src/mvPythonExceptions.cpp deleted file mode 100644 index fae79f9e3..000000000 --- a/src/mvPythonExceptions.cpp +++ /dev/null @@ -1,47 +0,0 @@ -#include "mvPythonExceptions.h" -#define PY_SSIZE_T_CLEAN -#include -#include -#include -#include "mvContext.h" -#include "mvAppItem.h" -#include "mvAppItemCommons.h" -#include "mvViewport.h" -#include "mvCallbackRegistry.h" -#include "mvGlobalIntepreterLock.h" - -void -mvThrowPythonError(mvErrorCode code, const std::string& message) -{ - std::string fullMessage = "Error: [%d] Message: \t" + message; - PyErr_Format(PyExc_Exception, fullMessage.c_str(), (int)code); -} - -void -mvThrowPythonError(mvErrorCode code, const std::string& command, const std::string& message, mvAppItem* item) -{ - if (item) - { - std::string fullMessage = "\nError: [%d]\nCommand: %s\nItem: %d \nLabel: %s\nItem Type: %s\nMessage: %s"; - PyErr_Format(PyExc_Exception, - fullMessage.c_str(), - (int)code, - command.c_str(), - item->uuid, - item->config.specifiedLabel.c_str(), - DearPyGui::GetEntityTypeString(item->type), - message.c_str()); - } - else - { - std::string fullMessage = "\nError: [%d]\nCommand: %s\nItem: %d \nLabel: %s\nItem Type: %s\nMessage: %s"; - PyErr_Format(PyExc_Exception, - fullMessage.c_str(), - (int)code, - command.c_str(), - 0, - "Not found", - "Unknown", - message.c_str()); - } -} \ No newline at end of file diff --git a/src/mvPythonExceptions.h b/src/mvPythonExceptions.h deleted file mode 100644 index 8795c710e..000000000 --- a/src/mvPythonExceptions.h +++ /dev/null @@ -1,25 +0,0 @@ -#pragma once - -#include - -// forward declarations -class mvAppItem; - -enum class mvErrorCode -{ - mvNone = 1000, - mvTextureNotFound = 1001, - mvIncompatibleType = 1002, - mvIncompatibleParent = 1003, - mvIncompatibleChild = 1004, - mvItemNotFound = 1005, - mvSourceNotFound = 1006, - mvSourceNotCompatible = 1007, - mvWrongType = 1008, - mvContainerStackEmpty = 1009, - mvStagingModeOff = 1010, - mvParentNotDeduced = 1011, -}; - -void mvThrowPythonError(mvErrorCode code, const std::string& message); -void mvThrowPythonError(mvErrorCode code, const std::string& command, const std::string& message, mvAppItem* item); \ No newline at end of file diff --git a/src/mvPythonParser.cpp b/src/mvPythonParser.cpp deleted file mode 100644 index fc47a25b7..000000000 --- a/src/mvPythonParser.cpp +++ /dev/null @@ -1,1190 +0,0 @@ -#include "mvPythonParser.h" -#include "mvAppItemCommons.h" -#include "dearpygui.h" -#include "mvContext.h" -#include -#include -#include -#include "mvPythonTypeChecker.h" -#include "mvPythonExceptions.h" -#include "mvPythonTranslator.h" - -static bool -VerifyArguments(int start, PyObject* args, const std::vector& elements) -{ - - if (start >= PyTuple_Size(args)) - return true; - - int end = (int)PyTuple_Size(args); - if (end > (int)elements.size()) - end = (int)elements.size(); - - for (int i = start; i < end; i++) - { - const auto& item = elements[i]; - PyObject* obj = nullptr; - obj = PyTuple_GetItem(args, i); - - switch (item.type) - { - case mvPyDataType::String: - if (!isPyObject_String(obj)) - return false; - break; - - case mvPyDataType::UUID: - { - if (isPyObject_Int(obj)) - break; - else if (isPyObject_String(obj)) - break; - return false; - } - - case mvPyDataType::Long: - case mvPyDataType::Integer: - if (!isPyObject_Int(obj)) - return false; - break; - - case mvPyDataType::Float: - if (!isPyObject_Float(obj)) - return false; - break; - - case mvPyDataType::Bool: - if (!isPyObject_Bool(obj)) - return false; - break; - - case mvPyDataType::StringList: - if (!isPyObject_StringList(obj)) - return false; - break; - - case mvPyDataType::FloatList: - if (!isPyObject_FloatList(obj)) - return false; - break; - - case mvPyDataType::IntList: - if (!isPyObject_IntList(obj)) - return false; - break; - - case mvPyDataType::Double: - if (!isPyObject_Double(obj)) - return false; - break; - - case mvPyDataType::Callable: - if (!isPyObject_Callable(obj)) - return false; - break; - - case mvPyDataType::Dict: - if (!isPyObject_Dict(obj)) - return false; - break; - - case mvPyDataType::ListFloatList: - if (!isPyObject_ListFloatList(obj)) - return false; - break; - - case mvPyDataType::ListStrList: - if (!isPyObject_ListStringList(obj)) - return false; - break; - - case mvPyDataType::ListListInt: - if (!isPyObject_ListIntList(obj)) - return false; - break; - - default: - if (!isPyObject_Any(obj)) - return false; - } - } - - return true; -} - -static char -PythonDataTypeSymbol(mvPyDataType type) -{ - switch (type) - { - //case mvPyDataType::UUID: return 'K'; - case mvPyDataType::Long: return 'l'; - case mvPyDataType::String: return 's'; - case mvPyDataType::Integer: return 'i'; - case mvPyDataType::Float: return 'f'; - case mvPyDataType::Double: return 'd'; - case mvPyDataType::Bool: return 'p'; - default: return 'O'; - } -} - -static const char* -PythonDataTypeString(mvPyDataType type) -{ - switch (type) - { - case mvPyDataType::String: return " : str"; - case mvPyDataType::UUID: return " : Union[int, str]"; - case mvPyDataType::Integer: return " : int"; - case mvPyDataType::Long: return " : int"; - case mvPyDataType::Float: return " : float"; - case mvPyDataType::Double: return " : float"; - case mvPyDataType::Bool: return " : bool"; - case mvPyDataType::StringList: return " : Union[List[str], Tuple[str, ...]]"; - case mvPyDataType::FloatList: return " : Union[List[float], Tuple[float, ...]]"; - case mvPyDataType::DoubleList: return " : Union[List[float], Tuple[float, ...]]"; - case mvPyDataType::IntList: return " : Union[List[int], Tuple[int, ...]]"; - case mvPyDataType::UUIDList: return " : Union[List[int], Tuple[int, ...]]"; - case mvPyDataType::Callable: return " : Callable"; - case mvPyDataType::Dict: return " : dict"; - case mvPyDataType::ListAny: return " : List[Any]"; - case mvPyDataType::ListListInt: return " : List[Union[List[int], Tuple[int, ...]]]"; - case mvPyDataType::ListFloatList: return " : List[List[float]]"; - case mvPyDataType::ListDoubleList: return " : List[List[float]]"; - case mvPyDataType::ListStrList: return " : List[List[str]]"; - case mvPyDataType::Object: return " : Any"; - default: return " : unknown"; - } -} - -const char* -PythonDataTypeActual(mvPyDataType type) -{ - switch (type) - { - case mvPyDataType::String: return "str"; - case mvPyDataType::UUID: return "Union[int, str]"; - case mvPyDataType::Integer: return "int"; - case mvPyDataType::Long: return "int"; - case mvPyDataType::Float: return "float"; - case mvPyDataType::Double: return "float"; - case mvPyDataType::Bool: return "bool"; - case mvPyDataType::StringList: return "Union[List[str], Tuple[str, ...]]"; - case mvPyDataType::FloatList: return "Union[List[float], Tuple[float, ...]]"; - case mvPyDataType::IntList: return "Union[List[int], Tuple[int, ...]]"; - case mvPyDataType::UUIDList: return "Union[List[int], Tuple[int, ...]]"; - case mvPyDataType::Callable: return "Callable"; - case mvPyDataType::Dict: return "dict"; - case mvPyDataType::ListFloatList: return "List[List[float]]"; - case mvPyDataType::ListStrList: return "List[List[str]]"; - case mvPyDataType::None: return "None"; - case mvPyDataType::Object: return "Any"; - default: return "Any"; - } -} - -mvPythonParser -FinalizeParser(const mvPythonParserSetup& setup, const std::vector& args) -{ - - mvPythonParser parser; - - // separate args into category - for (auto& arg : args) - { - switch (arg.arg_type) - { - case mvArgType::REQUIRED_ARG: - parser.required_elements.push_back(arg); - break; - case mvArgType::POSITIONAL_ARG: - parser.optional_elements.push_back(arg); - break; - case mvArgType::KEYWORD_ARG: - parser.keyword_elements.push_back(arg); - break; - default: - parser.deprecated_elements.push_back(arg); - } - } - - // build format string and keywords - if (!parser.required_elements.empty()) - { - for (auto& element : parser.required_elements) - { - parser.formatstring.push_back(PythonDataTypeSymbol(element.type)); - parser.keywords.push_back(element.name); - } - } - - parser.formatstring.push_back('|'); - - if (!parser.optional_elements.empty()) - { - - for (auto& element : parser.optional_elements) - { - parser.formatstring.push_back(PythonDataTypeSymbol(element.type)); - parser.keywords.push_back(element.name); - } - } - - if (!parser.keyword_elements.empty()) - { - parser.formatstring.push_back('$'); - for (auto& element : parser.keyword_elements) - { - parser.formatstring.push_back(PythonDataTypeSymbol(element.type)); - parser.keywords.push_back(element.name); - } - } - parser.formatstring.push_back(0); - parser.keywords.push_back(NULL); - - parser.about = setup.about; - parser.returnType = setup.returnType; - parser.category = setup.category; - parser.createContextManager = setup.createContextManager; - parser.unspecifiedKwargs = setup.unspecifiedKwargs; - parser.internal = setup.internal; - - // build documentation - std::string documentation = parser.about + "\n\nReturn Type: " + PythonDataTypeActual(parser.returnType) + "\n"; - - if (!parser.required_elements.empty()) - documentation += "\n\nRequired Arguments\n_______________\n\n"; - - for (const auto& element : parser.required_elements) - { - documentation += "\n* "; - documentation += element.name + std::string(PythonDataTypeString(element.type)); - documentation += "\n\t\t" + std::string(element.description); - } - - if (!parser.optional_elements.empty()) - documentation += "\n\nOptional Arguments\n_______________\n\n"; - - for (const auto& element : parser.optional_elements) - { - documentation += "\n* "; - documentation += element.name + std::string(PythonDataTypeString(element.type)); - documentation += " = " + std::string(element.default_value); - documentation += "\n\t\t" + std::string(element.description); - } - - if (!parser.keyword_elements.empty()) - documentation += "\n\nKeyword Arguments\n_______________\n\n"; - - for (const auto& element : parser.keyword_elements) - { - documentation += "\n* "; - documentation += element.name + std::string(PythonDataTypeString(element.type)); - documentation += " = " + std::string(element.default_value); - documentation += "\n\t\t" + std::string(element.description); - } - - if (!parser.keyword_elements.empty()) - documentation += "\n\nDeprecated Keyword Arguments\n_______________\n\n"; - - for (const auto& element : parser.deprecated_elements) - { - documentation += "\n* "; - documentation += element.name + std::string(PythonDataTypeString(element.type)); - documentation += " = " + std::string(element.default_value); - documentation += "\n\t\t" + std::string(element.description); - } - - parser.documentation = std::move(documentation); - - return parser; -} - -bool -VerifyRequiredArguments(const mvPythonParser& parser, PyObject* args) -{ - - // ensure enough args were provided - if ((size_t)PyTuple_Size(args) < parser.required_elements.size()) - { - assert(false && "Not enough arguments provided"); - mvThrowPythonError(mvErrorCode::mvNone, "Not enough arguments provided. Expected: " + - std::to_string(parser.required_elements.size()) + " Recieved: " + std::to_string((size_t)PyTuple_Size(args))); - return false; - } - - return VerifyArguments(0, args, parser.required_elements); -} - -bool -VerifyPositionalArguments(const mvPythonParser& parser, PyObject* args) -{ - return VerifyArguments((int)parser.optional_elements.size(), args, parser.optional_elements); -} - -bool -VerifyKeywordArguments(const mvPythonParser& parser, PyObject* args) -{ - if (args == nullptr) - return false; - - if (!PyArg_ValidateKeywordArguments(args)) - return false; - - PyObject* keys = PyDict_Keys(args); - - bool exists = false; - for (int i = 0; i < PyList_Size(keys); i++) - { - PyObject* item = PyList_GetItem(keys, i); - auto sitem = ToString(item); - - bool found = false; - for (const auto& keyword : parser.keyword_elements) - { - if (sitem == keyword.name) - { - found = true; - break; - } - } - - if (found) - continue; - else - { - for (const auto& keyword : parser.optional_elements) - { - if (sitem == keyword.name) - { - found = true; - break; - } - } - - if (found) - continue; - } - - for (const auto& keyword : parser.required_elements) - { - if (sitem == keyword.name) - { - found = true; - break; - } - } - - if (found) - continue; - - for (const auto& keyword : parser.deprecated_elements) - { - if (sitem == keyword.name) - { - found = true; - break; - } - } - - if (found) - continue; - - mvThrowPythonError(mvErrorCode::mvNone, sitem + " keyword does not exist."); - assert(false); - exists = false; - break; - } - - Py_XDECREF(keys); - - return exists; -} - -bool -VerifyArgumentCount(const mvPythonParser& parser, PyObject* args) -{ - if (args == nullptr && parser.required_elements.size() == 0) - return true; - if (args == nullptr) - { - mvThrowPythonError(mvErrorCode::mvNone, "This command has a minimum number of arguments of " + std::to_string(parser.required_elements.size())); - return false; - } - - int possibleArgs = (int)parser.required_elements.size() + (int)parser.optional_elements.size(); - int minArgs = (int)parser.required_elements.size(); - int numberOfArgs = (int)PyTuple_Size(args); - - if (numberOfArgs > possibleArgs) - { - mvThrowPythonError(mvErrorCode::mvNone, "This command has a maximum number of arguments of " + std::to_string(possibleArgs) + - " but recieved " + std::to_string(numberOfArgs)); - return false; - } - if (numberOfArgs < minArgs) - { - mvThrowPythonError(mvErrorCode::mvNone, "This command has a minimum number of arguments of " + std::to_string(minArgs) + - " but only recieved " + std::to_string(numberOfArgs)); - return false; - } - return true; -} - -bool -Parse(const mvPythonParser& parser, PyObject* args, PyObject* kwargs, const char* message, ...) -{ - - bool check = true; - - va_list arguments; - va_start(arguments, message); - if (!PyArg_VaParseTupleAndKeywords(args, kwargs, parser.formatstring.data(), - const_cast(parser.keywords.data()), arguments)) - { - check = false; - } - - va_end(arguments); - - if (!check) - mvThrowPythonError(mvErrorCode::mvNone, "Error parsing Dear PyGui command: " + std::string(message)); - - return check; -} - -void -GenerateStubFile(const std::string& directory) -{ - const auto& commands = GetModuleParsers(); - - std::ofstream stub; - stub.open(directory + "/_dearpygui.pyi"); - - stub << "from typing import List, Any, Callable, Union, Tuple\n"; - stub << "from dearpygui._dearpygui import *\n\n"; - stub << "##########################################################\n"; - stub << "# This file is generated automatically by mvPythonParser #\n"; - stub << "##########################################################\n\n"; - stub << "# ~ Dear PyGui Version: " << MV_SANDBOX_VERSION << "\n"; - - for (const auto& parser : commands) - { - stub << "def " << parser.first << "("; - - bool first_arg = true; - for (const auto& args : parser.second.required_elements) - { - if (first_arg) - first_arg = false; - else - stub << ", "; - stub << args.name << PythonDataTypeString(args.type); - } - - for (const auto& args : parser.second.optional_elements) - { - if (first_arg) - first_arg = false; - else - stub << ", "; - stub << args.name << PythonDataTypeString(args.type) << " =''"; - } - - if (!parser.second.keyword_elements.empty()) - { - if (first_arg) - first_arg = false; - else - stub << ", "; - - stub << "*"; - } - - for (const auto& args : parser.second.keyword_elements) - stub << ", " << args.name << ": " << PythonDataTypeActual(args.type) << " =''"; - - if (parser.second.unspecifiedKwargs) - stub << ", **kwargs"; - - stub << ") -> " << PythonDataTypeActual(parser.second.returnType) << ":"; - - stub << "\n\t\"\"\"" << parser.second.about.c_str() << "\"\"\""; - - stub << "\n\t...\n\n"; - } - - auto& constants = GetModuleConstants(); - - for (auto& item : constants) - stub << item.first << "=0\n"; - - stub.close(); -} - -void -GenerateCoreFile(std::ofstream& stream) -{ - const auto& commands = GetModuleParsers(); - - // current date/time based on current system - time_t now = time(0); - - // convert now to string form - char* dt = ctime(&now); - - for (const auto& parser : commands) - { - if (parser.second.internal) - continue; - - stream << "def " << parser.first << "("; - - bool first_arg = true; - for (const auto& args : parser.second.required_elements) - { - if (first_arg) - first_arg = false; - else - stream << ", "; - stream << args.name << PythonDataTypeString(args.type); - } - - for (const auto& args : parser.second.optional_elements) - { - if (first_arg) - first_arg = false; - else - stream << ", "; - stream << args.name << PythonDataTypeString(args.type) << " =" << args.default_value; - } - - if (!parser.second.keyword_elements.empty()) - { - if (first_arg) - first_arg = false; - else - stream << ", "; - - stream << "*"; - } - - for (const auto& args : parser.second.keyword_elements) - stream << ", " << args.name << ": " << PythonDataTypeActual(args.type) << " =" << args.default_value; - - if (first_arg) - stream << "**kwargs) -> "; - else - stream << ", **kwargs) -> "; - stream << PythonDataTypeActual(parser.second.returnType) << ":"; - - stream << "\n\t\"\"\"\t " << parser.second.about.c_str(); - - stream << "\n\n\tArgs:"; - for (const auto& args : parser.second.required_elements) - { - stream << "\n\t\t" << args.name << " (" << PythonDataTypeActual(args.type) << "): " << args.description; - } - - for (const auto& args : parser.second.optional_elements) - { - stream << "\n\t\t" << args.name << " (" << PythonDataTypeActual(args.type) << ", optional): " << args.description; - } - - for (const auto& args : parser.second.keyword_elements) - { - stream << "\n\t\t" << args.name << " (" << PythonDataTypeActual(args.type) << ", optional): " << args.description; - } - - for (const auto& args : parser.second.deprecated_elements) - { - stream << "\n\t\t" << args.name << " (" << PythonDataTypeActual(args.type) << ", optional): (deprecated) " << args.description; - } - - stream << "\n\tReturns:"; - stream << "\n\t\t" << PythonDataTypeActual(parser.second.returnType); - stream << "\n\t\"\"\""; - - - for (const auto& args : parser.second.deprecated_elements) - { - if (args.arg_type == mvArgType::DEPRECATED_REMOVE_KEYWORD_ARG) - { - stream << "\n\n\tif '" << args.name << "' in kwargs.keys():"; - stream << "\n\n\t\twarnings.warn('" << args.name << " keyword removed', DeprecationWarning, 2)"; - stream << "\n\n\t\tkwargs.pop('" << args.name << "', None)"; - } - - else if (args.arg_type == mvArgType::DEPRECATED_RENAME_KEYWORD_ARG) - { - stream << "\n\n\tif '" << args.name << "' in kwargs.keys():"; - stream << "\n\t\twarnings.warn('" << args.name << " keyword renamed to " << args.new_name << "', DeprecationWarning, 2)"; - stream << "\n\t\t" << args.new_name << "=kwargs['" << args.name << "']"; - } - } - - stream << "\n\n\treturn internal_dpg." << parser.first << "("; - - first_arg = true; - for (const auto& args : parser.second.required_elements) - { - if (first_arg) - first_arg = false; - else - stream << ", "; - stream << args.name; - } - - for (const auto& args : parser.second.optional_elements) - { - if (first_arg) - first_arg = false; - else - stream << ", "; - stream << args.name; - } - - for (const auto& args : parser.second.keyword_elements) - { - if (first_arg) - first_arg = false; - else - stream << ", "; - stream << args.name << "=" << args.name; - } - - if (first_arg) - stream << "**kwargs)\n\n"; - else - stream << ", **kwargs)\n\n"; - } -} - -void -GenerateContextsFile(std::ofstream& stream) -{ - const auto& commands = GetModuleParsers(); - - // current date/time based on current system - time_t now = time(0); - - // convert now to string form - char* dt = ctime(&now); - - for (const auto& parser : commands) - { - if (!parser.second.createContextManager) - continue; - - stream << "\n@contextmanager\n"; - stream << "def " << parser.first.substr(4) << "("; - - bool first_arg = true; - for (const auto& args : parser.second.required_elements) - { - if (first_arg) - first_arg = false; - else - stream << ", "; - stream << args.name << PythonDataTypeString(args.type); - } - - for (const auto& args : parser.second.optional_elements) - { - if (first_arg) - first_arg = false; - else - stream << ", "; - stream << args.name << PythonDataTypeString(args.type) << " =" << args.default_value; - } - - if (!parser.second.keyword_elements.empty()) - { - if (first_arg) - first_arg = false; - else - stream << ", "; - - stream << "*"; - } - - for (const auto& args : parser.second.keyword_elements) - stream << ", " << args.name << ": " << PythonDataTypeActual(args.type) << " =" << args.default_value; - - if (first_arg) - stream << "**kwargs) -> "; - else - stream << ", **kwargs) -> "; - stream << PythonDataTypeActual(parser.second.returnType) << ":"; - - stream << "\n\t\"\"\"\t " << parser.second.about.c_str(); - - stream << "\n\n\tArgs:"; - for (const auto& args : parser.second.required_elements) - { - stream << "\n\t\t" << args.name << " (" << PythonDataTypeActual(args.type) << "): " << args.description; - } - - for (const auto& args : parser.second.optional_elements) - { - stream << "\n\t\t" << args.name << " (" << PythonDataTypeActual(args.type) << ", optional): " << args.description; - } - - for (const auto& args : parser.second.keyword_elements) - { - stream << "\n\t\t" << args.name << " (" << PythonDataTypeActual(args.type) << ", optional): " << args.description; - } - - for (const auto& args : parser.second.deprecated_elements) - { - stream << "\n\t\t" << args.name << " (" << PythonDataTypeActual(args.type) << ", optional): (deprecated) " << args.description; - } - - stream << "\n\tYields:"; - stream << "\n\t\t" << PythonDataTypeActual(parser.second.returnType); - stream << "\n\t\"\"\""; - - stream << "\n\ttry:"; - - for (const auto& args : parser.second.deprecated_elements) - { - if (args.arg_type == mvArgType::DEPRECATED_REMOVE_KEYWORD_ARG) - { - stream << "\n\n\t\tif '" << args.name << "' in kwargs.keys():"; - stream << "\n\t\t\twarnings.warn('" << args.name << " keyword removed', DeprecationWarning, 2)"; - stream << "\n\t\t\tkwargs.pop('" << args.name << "', None)"; - } - - else if (args.arg_type == mvArgType::DEPRECATED_RENAME_KEYWORD_ARG) - { - stream << "\n\n\t\tif '" << args.name << "' in kwargs.keys():"; - stream << "\n\t\t\twarnings.warn('" << args.name << " keyword renamed to " << args.new_name << "', DeprecationWarning, 2)"; - stream << "\n\t\t\t" << args.new_name << "=kwargs['" << args.name << "']"; - } - } - - stream << "\n\t\twidget = internal_dpg." << parser.first << "("; - - first_arg = true; - for (const auto& args : parser.second.required_elements) - { - if (first_arg) - first_arg = false; - else - stream << ", "; - stream << args.name; - } - - for (const auto& args : parser.second.optional_elements) - { - if (first_arg) - first_arg = false; - else - stream << ", "; - stream << args.name; - } - - for (const auto& args : parser.second.keyword_elements) - { - if (first_arg) - first_arg = false; - else - stream << ", "; - stream << args.name << "=" << args.name; - } - - if (first_arg) - stream << "**kwargs)\n"; - else - stream << ", **kwargs)\n"; - - stream << "\t\tinternal_dpg.push_container_stack(widget)\n"; - stream << "\t\tyield widget\n"; - stream << "\tfinally:\n"; - stream << "\t\tinternal_dpg.pop_container_stack()\n"; - - } - -} - -void -GenerateCoreFileRTD(std::ofstream& stream) -{ - const auto& commands = GetModuleParsers(); - - // current date/time based on current system - time_t now = time(0); - - // convert now to string form - char* dt = ctime(&now); - - for (const auto& parser : commands) - { - if (parser.second.internal) - continue; - - stream << "def " << parser.first << "("; - - bool first_arg = true; - for (const auto& args : parser.second.required_elements) - { - if (first_arg) - first_arg = false; - else - stream << ", "; - stream << args.name; - } - - for (const auto& args : parser.second.optional_elements) - { - if (first_arg) - first_arg = false; - else - stream << ", "; - stream << args.name << "=" << args.default_value; - } - - if (parser.second.keyword_elements.empty()) - stream << "):"; - else - { - if(parser.second.required_elements.empty() && parser.second.optional_elements.empty()) - stream << "**kwargs):"; - else - stream << ", **kwargs):"; - } - - stream << "\n\t\"\"\"\t " << parser.second.about.c_str(); - - stream << "\n\n\tArgs:"; - for (const auto& args : parser.second.required_elements) - { - stream << "\n\t\t" << args.name << " (" << PythonDataTypeActual(args.type) << "): " << args.description; - } - - for (const auto& args : parser.second.optional_elements) - { - stream << "\n\t\t" << args.name << " (" << PythonDataTypeActual(args.type) << ", optional): " << args.description; - } - - for (const auto& args : parser.second.keyword_elements) - { - stream << "\n\t\t" << args.name << " (" << PythonDataTypeActual(args.type) << ", optional): " << args.description; - } - - for (const auto& args : parser.second.deprecated_elements) - { - stream << "\n\t\t" << args.name << " (" << PythonDataTypeActual(args.type) << ", optional): (deprecated)" << args.description; - } - - stream << "\n\tReturns:"; - stream << "\n\t\t" << PythonDataTypeActual(parser.second.returnType); - stream << "\n\t\"\"\""; - - stream << "\n\n\treturn internal_dpg." << parser.first << "("; - - first_arg = true; - for (const auto& args : parser.second.required_elements) - { - if (first_arg) - first_arg = false; - else - stream << ", "; - stream << args.name; - } - - for (const auto& args : parser.second.optional_elements) - { - if (first_arg) - first_arg = false; - else - stream << ", "; - stream << args.name; - } - - if (!parser.second.keyword_elements.empty()) - { - if (parser.second.required_elements.empty() && parser.second.optional_elements.empty()) - stream << "**kwargs"; - else - stream << ", **kwargs"; - } - - stream << ")\n\n"; - } -} - -void -GenerateContextsFileRTD(std::ofstream& stream) -{ - const auto& commands = GetModuleParsers(); - - // current date/time based on current system - time_t now = time(0); - - // convert now to string form - char* dt = ctime(&now); - - for (const auto& parser : commands) - { - if (!parser.second.createContextManager) - continue; - - stream << "\n@contextmanager\n"; - stream << "def " << parser.first.substr(4) << "("; - - bool first_arg = true; - for (const auto& args : parser.second.required_elements) - { - if (first_arg) - first_arg = false; - else - stream << ", "; - stream << args.name; - } - - for (const auto& args : parser.second.optional_elements) - { - if (first_arg) - first_arg = false; - else - stream << ", "; - stream << args.name << "=" << args.default_value; - } - - if (parser.second.keyword_elements.empty()) - stream << "):"; - else - { - if (parser.second.required_elements.empty() && parser.second.optional_elements.empty()) - stream << "**kwargs):"; - else - stream << ", **kwargs):"; - } - - stream << "\n\t\"\"\"\t " << parser.second.about.c_str(); - - stream << "\n\n\tArgs:"; - for (const auto& args : parser.second.required_elements) - { - stream << "\n\t\t" << args.name << " (" << PythonDataTypeActual(args.type) << "): " << args.description; - } - - for (const auto& args : parser.second.optional_elements) - { - stream << "\n\t\t" << args.name << " (" << PythonDataTypeActual(args.type) << ", optional): " << args.description; - } - - for (const auto& args : parser.second.keyword_elements) - { - stream << "\n\t\t" << args.name << " (" << PythonDataTypeActual(args.type) << ", optional): " << args.description; - } - - for (const auto& args : parser.second.deprecated_elements) - { - stream << "\n\t\t" << args.name << " (" << PythonDataTypeActual(args.type) << ", optional): (deprecated)" << args.description; - } - - stream << "\n\tYields:"; - stream << "\n\t\t" << PythonDataTypeActual(parser.second.returnType); - stream << "\n\t\"\"\""; - - stream << "\n\ttry:"; - stream << "\n\t\twidget = internal_dpg." << parser.first << "("; - - first_arg = true; - for (const auto& args : parser.second.required_elements) - { - if (first_arg) - first_arg = false; - else - stream << ", "; - stream << args.name; - } - - for (const auto& args : parser.second.optional_elements) - { - if (first_arg) - first_arg = false; - else - stream << ", "; - stream << args.name; - } - - if (!parser.second.keyword_elements.empty()) - { - if (parser.second.required_elements.empty() && parser.second.optional_elements.empty()) - stream << "**kwargs"; - else - stream << ", **kwargs"; - } - - stream << ")\n"; - stream << "\t\tinternal_dpg.push_container_stack(widget)\n"; - stream << "\t\tyield widget\n"; - stream << "\tfinally:\n"; - stream << "\t\tinternal_dpg.pop_container_stack()\n"; - - } - -} - -void -GenerateDearPyGuiFile(const std::string& directory) -{ - std::ofstream stub; - stub.open(directory + "/dearpygui.py"); - - stub << "\n##########################################################\n"; - stub << "# Dear PyGui User Interface\n"; - stub << "# ~ Version: " << MV_SANDBOX_VERSION << "\n"; - stub << "#\n"; - stub << "# Notes:\n"; - stub << "# * This file is automatically generated.\n#\n"; - stub << "# Resources:\n"; - stub << "# * FAQ: https://github.com/hoffstadt/DearPyGui/discussions/categories/frequently-asked-questions-faq \n"; - stub << "# * Homepage: https://github.com/hoffstadt/DearPyGui \n"; - stub << "# * Wiki: https://github.com/hoffstadt/DearPyGui/wiki \n"; - stub << "# * Issues: https://github.com/hoffstadt/DearPyGui/issues\n"; - stub << "# * Discussions: https://github.com/hoffstadt/DearPyGui/discussions\n"; - stub << "##########################################################\n\n"; - - std::ifstream inputStream0(directory + "/_header.py"); - - for (std::string line; std::getline(inputStream0, line);) - stub << line << "\n"; - - stub << "\n##########################################################\n"; - stub << "# Deprecated Commands\n"; - stub << "##########################################################\n"; - - std::ifstream inputStream1(directory + "/_deprecated.py"); - - for (std::string line; std::getline(inputStream1, line);) - stub << line << "\n"; - - stub << "\n##########################################################\n"; - stub << "# Container Context Managers\n"; - stub << "##########################################################\n\n"; - - GenerateContextsFile(stub); - - stub << "\n##########################################################\n"; - stub << "# Core Wrappings\n"; - stub << "##########################################################\n\n"; - - GenerateCoreFile(stub); - - stub << "\n##########################################################\n"; - stub << "# Constants #\n"; - stub << "##########################################################\n\n"; - - auto& constants = GetModuleConstants(); - - for (auto& item : constants) - stub << item.first << "=internal_dpg." << item.first << "\n"; - - stub.close(); - - std::ofstream redirect; - redirect.open(directory + "/_dearpygui.py"); - redirect << "from _dearpygui import *\n"; - redirect.close(); -} - -void -GenerateDearPyGuiFileRTD(const std::string& directory) -{ - std::ofstream stub; - stub.open(directory + "/_dearpygui_RTD.py"); - - stub << "\n##########################################################\n"; - stub << "# Dear PyGui User Interface (MODIFIED FOR READTHEDOCS)\n"; - stub << "# ~ Version: " << MV_SANDBOX_VERSION << "\n"; - stub << "#\n"; - stub << "# Notes:\n"; - stub << "# * This file is automatically generated.\n#\n"; - stub << "# Resources:\n"; - stub << "# * FAQ: https://github.com/hoffstadt/DearPyGui/discussions/categories/frequently-asked-questions-faq \n"; - stub << "# * Homepage: https://github.com/hoffstadt/DearPyGui \n"; - stub << "# * Wiki: https://github.com/hoffstadt/DearPyGui/wiki \n"; - stub << "# * Issues: https://github.com/hoffstadt/DearPyGui/issues\n"; - stub << "# * Discussions: https://github.com/hoffstadt/DearPyGui/discussions\n"; - stub << "##########################################################\n\n"; - - std::ifstream inputStream0(directory + "/_header.py"); - - for (std::string line; std::getline(inputStream0, line);) - stub << line << "\n"; - - stub << "\n##########################################################\n"; - stub << "# Deprecated Commands\n"; - stub << "##########################################################\n"; - - std::ifstream inputStream1(directory + "/_deprecated.py"); - - for (std::string line; std::getline(inputStream1, line);) - stub << line << "\n"; - - stub << "\n##########################################################\n"; - stub << "# Container Context Managers\n"; - stub << "##########################################################\n\n"; - - GenerateContextsFileRTD(stub); - - stub << "\n##########################################################\n"; - stub << "# Core Wrappings\n"; - stub << "##########################################################\n\n"; - - GenerateCoreFileRTD(stub); - - stub << "\n##########################################################\n"; - stub << "# Constants #\n"; - stub << "##########################################################\n\n"; - - auto& constants = GetModuleConstants(); - - for (auto& item : constants) - stub << item.first << "=internal_dpg." << item.first << "\n"; - - stub.close(); - - std::ofstream redirect; - redirect.open(directory + "/_dearpygui.py"); - redirect << "from _dearpygui import *\n"; - redirect.close(); -} - -void -AddCommonArgs(std::vector& args, CommonParserArgs argsFlags) -{ - - args.push_back({ mvPyDataType::UUID, "id", mvArgType::DEPRECATED_RENAME_KEYWORD_ARG, "0", "", "tag" }); - args.push_back({ mvPyDataType::String, "label", mvArgType::KEYWORD_ARG, "None", "Overrides 'name' as label." }); - args.push_back({ mvPyDataType::Object, "user_data", mvArgType::KEYWORD_ARG, "None", "User data for callbacks" }); - args.push_back({ mvPyDataType::Bool, "use_internal_label", mvArgType::KEYWORD_ARG, "True", "Use generated internal label instead of user specified (appends ### uuid)." }); - - if (argsFlags & MV_PARSER_ARG_ID) args.push_back({ mvPyDataType::UUID, "tag", mvArgType::KEYWORD_ARG, "0", "Unique id used to programmatically refer to the item.If label is unused this will be the label." }); - if (argsFlags & MV_PARSER_ARG_WIDTH) args.push_back({ mvPyDataType::Integer, "width", mvArgType::KEYWORD_ARG, "0", "Width of the item." }); - if (argsFlags & MV_PARSER_ARG_HEIGHT) args.push_back({ mvPyDataType::Integer, "height", mvArgType::KEYWORD_ARG, "0", "Height of the item." }); - if (argsFlags & MV_PARSER_ARG_INDENT) args.push_back({ mvPyDataType::Integer, "indent", mvArgType::KEYWORD_ARG, "-1", "Offsets the widget to the right the specified number multiplied by the indent style." }); - if (argsFlags & MV_PARSER_ARG_PARENT) args.push_back({ mvPyDataType::UUID, "parent", mvArgType::KEYWORD_ARG, "0", "Parent to add this item to. (runtime adding)" }); - if (argsFlags & MV_PARSER_ARG_BEFORE) args.push_back({ mvPyDataType::UUID, "before", mvArgType::KEYWORD_ARG, "0", "This item will be displayed before the specified item in the parent." }); - if (argsFlags & MV_PARSER_ARG_SOURCE) args.push_back({ mvPyDataType::UUID, "source", mvArgType::KEYWORD_ARG, "0", "Overrides 'id' as value storage key." }); - if (argsFlags & MV_PARSER_ARG_PAYLOAD_TYPE) args.push_back({ mvPyDataType::String, "payload_type", mvArgType::KEYWORD_ARG, "'$$DPG_PAYLOAD'", "Sender string type must be the same as the target for the target to run the payload_callback." }); - if (argsFlags & MV_PARSER_ARG_CALLBACK) args.push_back({ mvPyDataType::Callable, "callback", mvArgType::KEYWORD_ARG, "None", "Registers a callback." }); - if (argsFlags & MV_PARSER_ARG_DRAG_CALLBACK)args.push_back({ mvPyDataType::Callable, "drag_callback", mvArgType::KEYWORD_ARG, "None", "Registers a drag callback for drag and drop." }); - if (argsFlags & MV_PARSER_ARG_DROP_CALLBACK)args.push_back({ mvPyDataType::Callable, "drop_callback", mvArgType::KEYWORD_ARG, "None", "Registers a drop callback for drag and drop." }); - if (argsFlags & MV_PARSER_ARG_SHOW) args.push_back({ mvPyDataType::Bool, "show", mvArgType::KEYWORD_ARG, "True", "Attempt to render widget." }); - if (argsFlags & MV_PARSER_ARG_ENABLED) args.push_back({ mvPyDataType::Bool, "enabled", mvArgType::KEYWORD_ARG, "True", "Turns off functionality of widget and applies the disabled theme." }); - if (argsFlags & MV_PARSER_ARG_POS) args.push_back({ mvPyDataType::IntList, "pos", mvArgType::KEYWORD_ARG, "[]", "Places the item relative to window coordinates, [0,0] is top left." }); - if (argsFlags & MV_PARSER_ARG_FILTER) args.push_back({ mvPyDataType::String, "filter_key", mvArgType::KEYWORD_ARG, "''", "Used by filter widget." }); - if (argsFlags & MV_PARSER_ARG_SEARCH_DELAY) args.push_back({ mvPyDataType::Bool, "delay_search", mvArgType::KEYWORD_ARG, "False", "Delays searching container for specified items until the end of the app. Possible optimization when a container has many children that are not accessed often." }); - - if (argsFlags & MV_PARSER_ARG_TRACKED) - { - args.push_back({ mvPyDataType::Bool, "tracked", mvArgType::KEYWORD_ARG, "False", "Scroll tracking" }); - args.push_back({ mvPyDataType::Float, "track_offset", mvArgType::KEYWORD_ARG, "0.5", "0.0f:top, 0.5f:center, 1.0f:bottom" }); - } - -} \ No newline at end of file diff --git a/src/mvPythonParser.h b/src/mvPythonParser.h deleted file mode 100644 index 9e4b84bcf..000000000 --- a/src/mvPythonParser.h +++ /dev/null @@ -1,123 +0,0 @@ -#pragma once - -//----------------------------------------------------------------------------- -// mvPythonParser -// -// - This class has the following responsibilities: -// -// * Assist in Python tuple parsing and error checks the operation -// * Builds documentation based on PythonDataElement List -// * Categorizes Python Commands -// * Builds the Python parse string -// -// - Should probably be reworked for v1.0 to be clearer -// -//----------------------------------------------------------------------------- - -#include -#include -#include -#include -#include -#include - -// forward declare PyObject -// as suggested on the python mailing list -// http://mail.python.org/pipermail/python-dev/2003-August/037601.html -#ifndef PyObject_HEAD -struct _object; -typedef _object PyObject; -#endif - -enum class mvPyDataType -{ - None = 0, - Integer, Float, Double, String, Bool, Object, Callable, Dict, - IntList, FloatList, DoubleList, StringList, ListAny, - ListListInt, ListFloatList, ListDoubleList, ListStrList, UUID, - UUIDList, Long, - Any -}; - -enum class mvArgType -{ - REQUIRED_ARG = 0, - POSITIONAL_ARG, - KEYWORD_ARG, - DEPRECATED_RENAME_KEYWORD_ARG, - DEPRECATED_REMOVE_KEYWORD_ARG -}; - -enum CommonParserArgs -{ - MV_PARSER_ARG_ID = 1 << 1, - MV_PARSER_ARG_WIDTH = 1 << 2, - MV_PARSER_ARG_HEIGHT = 1 << 3, - MV_PARSER_ARG_INDENT = 1 << 4, - MV_PARSER_ARG_PARENT = 1 << 5, - MV_PARSER_ARG_BEFORE = 1 << 6, - MV_PARSER_ARG_SOURCE = 1 << 7, - MV_PARSER_ARG_CALLBACK = 1 << 8, - MV_PARSER_ARG_SHOW = 1 << 9, - MV_PARSER_ARG_ENABLED = 1 << 10, - MV_PARSER_ARG_POS = 1 << 11, - MV_PARSER_ARG_DROP_CALLBACK = 1 << 12, - MV_PARSER_ARG_DRAG_CALLBACK = 1 << 13, - MV_PARSER_ARG_PAYLOAD_TYPE = 1 << 14, - MV_PARSER_ARG_TRACKED = 1 << 15, - MV_PARSER_ARG_FILTER = 1 << 16, - MV_PARSER_ARG_SEARCH_DELAY = 1 << 17 -}; - -struct mvPythonDataElement -{ - mvPyDataType type = mvPyDataType::None; - const char* name = ""; - mvArgType arg_type = mvArgType::REQUIRED_ARG; - const char* default_value = "..."; - const char* description = ""; - const char* new_name = ""; -}; - -struct mvPythonParser -{ - std::vector required_elements; - std::vector optional_elements; - std::vector keyword_elements; - std::vector deprecated_elements; - std::vector formatstring; - std::vector keywords; - std::string documentation; - bool unspecifiedKwargs = false; - bool createContextManager = false; - bool internal = false; - std::string about; - mvPyDataType returnType = mvPyDataType::None; - std::vector category; -}; - -struct mvPythonParserSetup -{ - std::string about = "Undocumented"; - mvPyDataType returnType = mvPyDataType::None; - std::vector category = {"General"}; - bool createContextManager = false; - bool unspecifiedKwargs = false; - bool internal = false; -}; - -mvPythonParser FinalizeParser(const mvPythonParserSetup& setup, const std::vector& args); -bool Parse(const mvPythonParser& parser, PyObject* args, PyObject* kwargs, const char* message, ...); -const char* PythonDataTypeActual(mvPyDataType type); -void AddCommonArgs(std::vector& args, CommonParserArgs argsFlags); - -// arguments checks -bool VerifyRequiredArguments (const mvPythonParser& parser, PyObject* args); -bool VerifyPositionalArguments(const mvPythonParser& parser, PyObject* args); -bool VerifyKeywordArguments (const mvPythonParser& parser, PyObject* args); -bool VerifyArgumentCount (const mvPythonParser& parser, PyObject* args); - -// file generation -void GenerateStubFile (const std::string& directory); -void GenerateDearPyGuiFile (const std::string& directory); -void GenerateDearPyGuiFileRTD(const std::string& directory); \ No newline at end of file diff --git a/src/mvPythonTranslator.cpp b/src/mvPythonTranslator.cpp deleted file mode 100644 index 1a59e52f4..000000000 --- a/src/mvPythonTranslator.cpp +++ /dev/null @@ -1,1360 +0,0 @@ -#include "mvPythonTranslator.h" -#include "mvPythonExceptions.h" -#include "mvPythonTypeChecker.h" -#include "mvContext.h" -#include "mvItemRegistry.h" - -#define PY_SSIZE_T_CLEAN -#include - -void -UpdatePyIntList(PyObject* pyvalue, const std::vector& value) -{ - if (pyvalue == nullptr) - return; - - - if (!PyList_Check(pyvalue)) - { - mvThrowPythonError(mvErrorCode::mvWrongType, "Python value error"); - return; - } - - - for (Py_ssize_t i = 0; i < PyList_Size(pyvalue); ++i) - { - if (static_cast(i) == value.size()) - break; - PyList_SetItem(pyvalue, i, PyLong_FromLong(value[i])); - } -} - -void -UpdatePyFloatList(PyObject* pyvalue, const std::vector& value) -{ - if (pyvalue == nullptr) - return; - - - if (!PyList_Check(pyvalue)) - { - mvThrowPythonError(mvErrorCode::mvWrongType, "Python value error"); - return; - } - - - for (Py_ssize_t i = 0; i < PyList_Size(pyvalue); ++i) - { - if (static_cast(i) == value.size()) - break; - PyList_SetItem(pyvalue, i, PyFloat_FromDouble(value[i])); - } -} - -void -UpdatePyStringStringList(PyObject* pyvalue, const std::vector>& value) -{ - if (pyvalue == nullptr) - return; - - - if (!PyList_Check(pyvalue)) - { - mvThrowPythonError(mvErrorCode::mvWrongType, "Python value error"); - return; - } - - - for (Py_ssize_t i = 0; i < PyList_Size(pyvalue); ++i) - { - if (static_cast(i) == value.size()) - break; - PyObject* row = PyList_GetItem(pyvalue, i); - for (Py_ssize_t j = 0; j < PyList_Size(row); ++j) - { - if (static_cast(j) == value[i].size()) - break; - PyList_SetItem(row, i, PyUnicode_FromString(value[i][j].c_str())); - } - } -} - -PyObject* -GetPyNone() -{ - Py_RETURN_NONE; -} - -PyObject* -ToPyString(const std::string& value) -{ - - return PyUnicode_FromString(value.c_str()); -} - -PyObject* -ToPyFloat(float value) -{ - - return PyFloat_FromDouble(value); -} - -PyObject* -ToPyDouble(double value) -{ - - return PyFloat_FromDouble(value); -} - -PyObject* -ToPyInt(int value) -{ - - return PyLong_FromLong(value); -} - -PyObject* -ToPyUUID(mvAppItem* item) -{ - - if (!item->config.alias.empty()) - return ToPyString(item->config.alias); - - return Py_BuildValue("K", item->uuid); -} - -PyObject* -ToPyUUID(mvUUID value) -{ - mvAppItem* item = GetItem(*GContext->itemRegistry, value); - if (item) - { - if (!item->config.alias.empty()) - return ToPyString(item->config.alias); - } - return Py_BuildValue("K", value); -} - -PyObject* -ToPyLong(long value) -{ - - return Py_BuildValue("K", value); -} - -PyObject* -ToPyBool(bool value) -{ - - return PyBool_FromLong(value); -} - -PyObject* -ToPyMPair(int x, float y) -{ - - return Py_BuildValue("[if]", x, y); -} - -PyObject* -ToPyMTrip(int i, float x, float y) -{ - - return Py_BuildValue("[iff]", i, x, y); -} - -PyObject* -ToPyPair(float x, float y) -{ - - return Py_BuildValue("[ff]", x, y); -} - -PyObject* -ToPyPairII(int x, int y) -{ - - return Py_BuildValue("[ii]", x, y); -} - -PyObject* -ToPyPair(double x, double y) -{ - - return Py_BuildValue("[dd]", x, y); -} - -PyObject* -ToPyPair(const std::string& x, const std::string& y) -{ - - return Py_BuildValue("[ss]", x.c_str(), y.c_str()); -} - -PyObject* -ToPyList(const std::vector& value) -{ - - - PyObject* result = PyList_New(value.size()); - - for (size_t i = 0; i < value.size(); ++i) - PyList_SetItem(result, i, PyLong_FromLong(value[i])); - - return result; -} - -PyObject* -ToPyList(const std::vector& value) -{ - - - PyObject* result = PyList_New(value.size()); - - for (size_t i = 0; i < value.size(); ++i) - PyList_SetItem(result, i, Py_BuildValue("K", value[i])); - - return result; -} - -PyObject* -ToPyList(const std::vector& value) -{ - - - PyObject* result = PyList_New(value.size()); - - for (size_t i = 0; i < value.size(); ++i) - { - PyObject* item = PyList_New(2); - PyList_SetItem(item, 0, PyFloat_FromDouble (value[i].x)); - PyList_SetItem(item, 1, PyFloat_FromDouble (value[i].y)); - PyList_SetItem(item, i, item); - } - - return result; -} - -PyObject* -ToPyList(const std::vector& value) -{ - - - PyObject* result = PyList_New(value.size()); - - for (size_t i = 0; i < value.size(); ++i) - { - PyObject* item = PyList_New(4); - PyList_SetItem(item, 0, PyFloat_FromDouble(value[i].x)); - PyList_SetItem(item, 1, PyFloat_FromDouble(value[i].y)); - PyList_SetItem(item, 2, PyFloat_FromDouble(value[i].z)); - PyList_SetItem(item, 3, PyFloat_FromDouble(value[i].w)); - PyList_SetItem(item, i, item); - } - - return result; -} - -PyObject* -ToPyList(const std::vector& value) -{ - - PyObject* result = PyList_New(value.size()); - - for (size_t i = 0; i < value.size(); ++i) - PyList_SetItem(result, i, PyFloat_FromDouble(value[i])); - - return result; -} - -PyObject* -ToPyList(const std::vector& value) -{ - - PyObject* result = PyList_New(value.size()); - - if(result) - { - for (size_t i = 0; i < value.size(); ++i) - PyList_SetItem(result, i, PyFloat_FromDouble(value[i])); - } - return result; -} - -PyObject* -ToPyList(const std::vector>& value) -{ - PyObject* result = PyList_New(value.size()); - - if(result) - { - for (size_t i = 0; i < value.size(); ++i) - PyList_SetItem(result, i, ToPyList(value[i])); - } - - return result; -} - -PyObject* -ToPyList(const std::vector>& value) -{ - PyObject* result = PyList_New(value.size()); - - if(result) - { - for (size_t i = 0; i < value.size(); ++i) - PyList_SetItem(result, i, ToPyList(value[i])); - } - - return result; -} - -PyObject* -ToPyList(const std::vector& value) -{ - - - PyObject* result = PyList_New(value.size()); - - for (size_t i = 0; i < value.size(); ++i) - PyList_SetItem(result, i, PyUnicode_FromString(value[i].c_str())); - - return result; -} - -PyObject* -ToPyList(const std::vector>& value) -{ - - - PyObject* result = PyList_New(value.size()); - - for (size_t i = 0; i < value.size(); ++i) - PyList_SetItem(result, i, ToPyList(value[i])); - - return result; -} - -PyObject* -ToPyList(const std::vector>& value) -{ - PyObject* result = PyList_New(value.size()); - - for (size_t i = 0; i < value.size(); ++i) - PyList_SetItem(result, i, ToPyPairII(value[i].first, value[i].second)); - - return result; -} - -PyObject* -ToPyList(const std::vector>& value) -{ - PyObject* result = PyList_New(value.size()); - - for (size_t i = 0; i < value.size(); ++i) - PyList_SetItem(result, i, ToPyPair(value[i].first, value[i].second)); - - return result; -} - -PyObject* -ToPyColor(const mvColor& color) -{ - - - PyObject* result = PyList_New(4); - - PyList_SetItem(result, 0, ToPyFloat((float)color.r)); - PyList_SetItem(result, 1, ToPyFloat((float)color.g)); - PyList_SetItem(result, 2, ToPyFloat((float)color.b)); - PyList_SetItem(result, 3, ToPyFloat((float)color.a)); - - return result; -} - -PyObject* -ToPyTime(const tm& time) -{ - - PyObject* dict = PyDict_New(); - PyDict_SetItemString(dict, "sec", mvPyObject(ToPyInt(time.tm_sec))); - PyDict_SetItemString(dict, "min", mvPyObject(ToPyInt(time.tm_min))); - PyDict_SetItemString(dict, "hour", mvPyObject(ToPyInt(time.tm_hour))); - PyDict_SetItemString(dict, "month_day", mvPyObject(ToPyInt(time.tm_mday))); - PyDict_SetItemString(dict, "month", mvPyObject(ToPyInt(time.tm_mon))); - PyDict_SetItemString(dict, "year", mvPyObject(ToPyInt(time.tm_year))); - PyDict_SetItemString(dict, "week_day", mvPyObject(ToPyInt(time.tm_wday))); - PyDict_SetItemString(dict, "year_day", mvPyObject(ToPyInt(time.tm_yday))); - PyDict_SetItemString(dict, "daylight_savings", mvPyObject(ToPyInt(time.tm_isdst))); - return dict; -} - -PyObject* -ToPyIntList(const int* value, int count) -{ - - - PyObject* result = PyList_New(count); - - for (int i = 0; i < count; ++i) - PyList_SetItem(result, i, PyLong_FromLong(value[i])); - - return result; -} - -PyObject* -ToPyFloatList(const float* value, int count) -{ - - - PyObject* result = PyList_New(count); - - for (int i = 0; i < count; ++i) - PyList_SetItem(result, i, PyFloat_FromDouble(value[i])); - - return result; -} - -PyObject* -ToPyFloatList(const double* value, int count) -{ - - - PyObject* result = PyList_New(count); - - for (int i = 0; i < count; ++i) - PyList_SetItem(result, i, PyFloat_FromDouble(value[i])); - - return result; -} - -tm -ToTime(PyObject* value, const std::string& message) -{ - tm result = {}; - if (value == nullptr) - return result; - - if (!PyDict_Check(value)) - { - mvThrowPythonError(mvErrorCode::mvWrongType, "Python value error. Must be dict/time."); - return result; - } - - if (PyObject* item = PyDict_GetItemString(value, "sec")) result.tm_sec = ToInt(item); - if (PyObject* item = PyDict_GetItemString(value, "min")) result.tm_min = ToInt(item); - if (PyObject* item = PyDict_GetItemString(value, "hour")) result.tm_hour = ToInt(item); - if (PyObject* item = PyDict_GetItemString(value, "month_day")) result.tm_mday = ToInt(item); - else result.tm_mday = 1; - if (PyObject* item = PyDict_GetItemString(value, "month")) result.tm_mon = ToInt(item); - if (PyObject* item = PyDict_GetItemString(value, "year")) result.tm_year = ToInt(item); - else result.tm_year = 70; - if (PyObject* item = PyDict_GetItemString(value, "week_day")) result.tm_wday = ToInt(item); - if (PyObject* item = PyDict_GetItemString(value, "year_day")) result.tm_yday = ToInt(item); - if (PyObject* item = PyDict_GetItemString(value, "daylight_savings")) result.tm_isdst = ToInt(item); - - return result; -} - -int -ToInt(PyObject* value, const std::string& message) -{ - if (value == nullptr) - return 0; - - - if (PyLong_Check(value)) - return PyLong_AsLong(value); - - else if (PyFloat_Check(value)) - return (int)PyFloat_AsDouble(value); - - mvThrowPythonError(mvErrorCode::mvWrongType, "Python value error. Must be int."); - return 0; -} - -mvUUID -ToUUID(PyObject* value, const std::string& message) -{ - if (value == nullptr) - return 0; - - if (PyUnicode_Check(value)) - { - std::string result = _PyUnicode_AsString(value); - mvUUID idfound = GetIdFromAlias(*GContext->itemRegistry, result); - if (idfound == 0) - { - mvThrowPythonError(mvErrorCode::mvWrongType, "UUID not found."); - return 0; - } - return idfound; - } - - if (!PyLong_Check(value)) - { - mvThrowPythonError(mvErrorCode::mvWrongType, "Python value error. Must be int."); - return 0; - } - - return PyLong_AsUnsignedLongLong(value); -} - -float -ToFloat(PyObject* value, const std::string& message) -{ - if (value == nullptr) - return 0.0f; - - - if (!PyNumber_Check(value)) - { - mvThrowPythonError(mvErrorCode::mvWrongType, "Python value error. Must be float."); - return 0.0f; - } - - if (PyLong_Check(value)) - { - return (float)PyLong_AsLong(value); - } - - return (float)PyFloat_AsDouble(value); -} - -double -ToDouble(PyObject* value, const std::string& message) -{ - if (value == nullptr) - return 0.0; - - - if (!PyNumber_Check(value)) - { - mvThrowPythonError(mvErrorCode::mvWrongType, "Python value error. Must be double."); - return 0.0; - } - - return PyFloat_AsDouble(value); -} - -bool -ToBool(PyObject* value, const std::string& message) -{ - if (value == nullptr) - return false; - - - if (!PyBool_Check(value)) - { - mvThrowPythonError(mvErrorCode::mvWrongType, "Python value error. Must be bool."); - return false; - } - - return PyLong_AsLong(value); -} - -std::string -ToString(PyObject* value, const std::string& message) -{ - std::string result; - if (value == nullptr) - return result; - - if (PyUnicode_Check(value)) - { - result = _PyUnicode_AsString(value); - } - else - { - PyObject* str = PyObject_Str(value); - if (str == nullptr) - { - mvThrowPythonError(mvErrorCode::mvWrongType, "Python value error. Must be string."); - return ""; - } - result = _PyUnicode_AsString(str); - Py_XDECREF(str); - } - - return result; - -} - -static std::function -BufferViewFunctionsFloat(Py_buffer& bufferView) -{ - if (strcmp(bufferView.format, "f") == 0) - return [](Py_buffer& bufferView, Py_ssize_t index) {return *((float*)bufferView.buf + index); }; - - else if (strcmp(bufferView.format, "d") == 0) - return [](Py_buffer& bufferView, Py_ssize_t index) {return (float)*((double*)bufferView.buf + index); }; - - else if (strcmp(bufferView.format, "i") == 0) - return [](Py_buffer& bufferView, Py_ssize_t index) {return (float)*((int*)bufferView.buf + index); }; - - else if (strcmp(bufferView.format, "I") == 0) - return [](Py_buffer& bufferView, Py_ssize_t index) {return (float)*((unsigned int*)bufferView.buf + index); }; - - else if (strcmp(bufferView.format, "l") == 0) - return [](Py_buffer& bufferView, Py_ssize_t index) {return (float)*((long*)bufferView.buf + index); }; - - else if (strcmp(bufferView.format, "L") == 0) - return [](Py_buffer& bufferView, Py_ssize_t index) {return (float)*((long long*)bufferView.buf + index); }; - - else if (strcmp(bufferView.format, "k") == 0) - return [](Py_buffer& bufferView, Py_ssize_t index) {return (float)*((unsigned long*)bufferView.buf + index); }; - - else if (strcmp(bufferView.format, "K") == 0) - return [](Py_buffer& bufferView, Py_ssize_t index) {return (float)*((unsigned long long*)bufferView.buf + index); }; - - else if (strcmp(bufferView.format, "B") == 0) - return [](Py_buffer& bufferView, Py_ssize_t index) {return (float)*((unsigned char*)bufferView.buf + index); }; - - else if (strcmp(bufferView.format, "b") == 0) - return [](Py_buffer& bufferView, Py_ssize_t index) {return (float)*((signed char*)bufferView.buf + index); }; - - else if (strcmp(bufferView.format, "c") == 0) - return [](Py_buffer& bufferView, Py_ssize_t index) {return (float)*((char*)bufferView.buf + index); }; - else - { - mvThrowPythonError(mvErrorCode::mvWrongType, "Unknown buffer type."); - mvThrowPythonError(mvErrorCode::mvWrongType, bufferView.format); - mvThrowPythonError(mvErrorCode::mvWrongType, "Currently supported buffer types f, d, l, B"); - return nullptr; - } -} - -static std::function -BufferViewFunctionsInt(Py_buffer& bufferView) -{ - if (strcmp(bufferView.format, "f") == 0) - return [](Py_buffer& bufferView, Py_ssize_t index) {return (int)*((float*)bufferView.buf + index); }; - - else if (strcmp(bufferView.format, "d") == 0) - return [](Py_buffer& bufferView, Py_ssize_t index) {return (int)*((double*)bufferView.buf + index); }; - - else if (strcmp(bufferView.format, "i") == 0) - return [](Py_buffer& bufferView, Py_ssize_t index) {return (int)*((int*)bufferView.buf + index); }; - - else if (strcmp(bufferView.format, "I") == 0) - return [](Py_buffer& bufferView, Py_ssize_t index) {return (int)*((unsigned int*)bufferView.buf + index); }; - - else if (strcmp(bufferView.format, "l") == 0) - return [](Py_buffer& bufferView, Py_ssize_t index) {return (int)*((long*)bufferView.buf + index); }; - - else if (strcmp(bufferView.format, "L") == 0) - return [](Py_buffer& bufferView, Py_ssize_t index) {return (int)*((long long*)bufferView.buf + index); }; - - else if (strcmp(bufferView.format, "k") == 0) - return [](Py_buffer& bufferView, Py_ssize_t index) {return (int)*((unsigned long*)bufferView.buf + index); }; - - else if (strcmp(bufferView.format, "K") == 0) - return [](Py_buffer& bufferView, Py_ssize_t index) {return (int)*((unsigned long long*)bufferView.buf + index); }; - - else if (strcmp(bufferView.format, "B") == 0) - return [](Py_buffer& bufferView, Py_ssize_t index) {return (int)*((unsigned char*)bufferView.buf + index); }; - - else if (strcmp(bufferView.format, "b") == 0) - return [](Py_buffer& bufferView, Py_ssize_t index) {return (int)*((signed char*)bufferView.buf + index); }; - - else if (strcmp(bufferView.format, "c") == 0) - return [](Py_buffer& bufferView, Py_ssize_t index) {return (int)*((char*)bufferView.buf + index); }; - else - { - mvThrowPythonError(mvErrorCode::mvWrongType, "Unknown buffer type."); - mvThrowPythonError(mvErrorCode::mvWrongType, bufferView.format); - mvThrowPythonError(mvErrorCode::mvWrongType, "Currently supported buffer types f, d, l, B"); - return nullptr; - } -} - -std::vector -ToUCharVect(PyObject* value, const std::string& message) -{ - std::vector items; - if (value == nullptr) - return items; - - if (PyTuple_Check(value)) - { - items.resize(PyTuple_Size(value)); - for (Py_ssize_t i = 0; i < PyTuple_Size(value); ++i) - { - items[i] = (unsigned char)PyLong_AsLong(PyTuple_GetItem(value, i)); - } - } - - else if (PyList_Check(value)) - { - items.resize(PyList_Size(value)); - for (Py_ssize_t i = 0; i < PyList_Size(value); ++i) - { - items[i] = (unsigned char)PyLong_AsLong(PyList_GetItem(value, i)); - } - } - - else if (PyObject_CheckBuffer(value)) - { - - - Py_buffer buffer_info; - - if (!PyObject_GetBuffer(value, &buffer_info, - PyBUF_CONTIG_RO | PyBUF_FORMAT)) - { - auto BufferViewer = BufferViewFunctionsInt(buffer_info); - - for (Py_ssize_t i = 0; i < buffer_info.len / buffer_info.itemsize; ++i) - { - items.emplace_back((unsigned char)BufferViewer(buffer_info, i)); - } - } - - PyBuffer_Release(&buffer_info); - } - - else - mvThrowPythonError(mvErrorCode::mvWrongType, "Python value error. Must be List[int]."); - - - return items; -} - -std::vector -ToIntVect(PyObject* value, const std::string& message) -{ - - std::vector items; - if (value == nullptr) - return items; - - if (PyTuple_Check(value)) - { - items.resize(PyTuple_Size(value)); - for (Py_ssize_t i = 0; i < PyTuple_Size(value); ++i) - { - items[i] = PyLong_AsLong(PyTuple_GetItem(value, i)); - } - } - - else if (PyList_Check(value)) - { - items.resize(PyList_Size(value)); - for (Py_ssize_t i = 0; i < PyList_Size(value); ++i) - { - items[i] = PyLong_AsLong(PyList_GetItem(value, i)); - } - } - - else if (PyObject_CheckBuffer(value)) - { - - - Py_buffer buffer_info; - - if (!PyObject_GetBuffer(value, &buffer_info, - PyBUF_CONTIG_RO | PyBUF_FORMAT)) - { - auto BufferViewer = BufferViewFunctionsInt(buffer_info); - - for (Py_ssize_t i = 0; i < buffer_info.len / buffer_info.itemsize; ++i) - { - items.emplace_back(BufferViewer(buffer_info, i)); - } - } - - PyBuffer_Release(&buffer_info); - } - - else - mvThrowPythonError(mvErrorCode::mvWrongType, "Python value error. Must be List[int]."); - - - return items; -} - -std::vector -ToUUIDVect(PyObject* value, const std::string& message) -{ - - std::vector items; - if (value == nullptr) - return items; - - - if (PyTuple_Check(value)) - { - items.resize(PyTuple_Size(value)); - for (Py_ssize_t i = 0; i < PyTuple_Size(value); ++i) - { - PyObject* item = PyTuple_GetItem(value, i); - if (isPyObject_Int(item)) - items[i] = PyLong_AsUnsignedLongLong(item); - else if (isPyObject_String(item)) - items[i] = GetIdFromAlias(*GContext->itemRegistry, ToString(item)); - } - } - - else if (PyList_Check(value)) - { - items.resize(PyList_Size(value)); - for (Py_ssize_t i = 0; i < PyList_Size(value); ++i) - { - PyObject* item = PyList_GetItem(value, i); - if (isPyObject_Int(item)) - items[i] = PyLong_AsUnsignedLongLong(item); - else if (isPyObject_String(item)) - items[i] = GetIdFromAlias(*GContext->itemRegistry, ToString(item)); - } - } - - else - mvThrowPythonError(mvErrorCode::mvWrongType, "Python value error. Must be List[int]."); - - - return items; -} - -std::vector -ToFloatVect(PyObject* value, const std::string& message) -{ - - std::vector items; - if (value == nullptr) - return items; - - - if (PyTuple_Check(value)) - { - for (Py_ssize_t i = 0; i < PyTuple_Size(value); ++i) - { - items.emplace_back((float)PyFloat_AsDouble(PyTuple_GetItem(value, i))); - } - } - - else if (PyList_Check(value)) - { - for (Py_ssize_t i = 0; i < PyList_Size(value); ++i) - { - items.emplace_back((float)PyFloat_AsDouble(PyList_GetItem(value, i))); - } - } - - else if (PyObject_CheckBuffer(value)) - { - Py_buffer buffer_info; - - if (!PyObject_GetBuffer(value, &buffer_info, - PyBUF_CONTIG_RO | PyBUF_FORMAT)) - { - - auto BufferViewer = BufferViewFunctionsFloat(buffer_info); - items.reserve(buffer_info.len / buffer_info.itemsize); - - for (Py_ssize_t i = 0; i < buffer_info.len / buffer_info.itemsize; ++i) - { - items.emplace_back(BufferViewer(buffer_info, i)); - } - } - PyBuffer_Release(&buffer_info); - } - - else - mvThrowPythonError(mvErrorCode::mvWrongType, "Python value error. Must be List[float]."); - - - return items; -} - -std::vector -ToDoubleVect(PyObject* value, const std::string& message) -{ - - std::vector items; - if (value == nullptr) - return items; - - - if (PyTuple_Check(value)) - { - for (Py_ssize_t i = 0; i < PyTuple_Size(value); ++i) - { - items.emplace_back(PyFloat_AsDouble(PyTuple_GetItem(value, i))); - } - } - - else if (PyList_Check(value)) - { - for (Py_ssize_t i = 0; i < PyList_Size(value); ++i) - { - items.emplace_back(PyFloat_AsDouble(PyList_GetItem(value, i))); - } - } - - else if (PyObject_CheckBuffer(value)) - { - Py_buffer buffer_info; - - if (!PyObject_GetBuffer(value, &buffer_info, - PyBUF_CONTIG_RO | PyBUF_FORMAT)) - { - - auto BufferViewer = BufferViewFunctionsFloat(buffer_info); - - for (Py_ssize_t i = 0; i < buffer_info.len / buffer_info.itemsize; ++i) - { - items.emplace_back(BufferViewer(buffer_info, i)); - } - } - PyBuffer_Release(&buffer_info); - } - - else - mvThrowPythonError(mvErrorCode::mvWrongType, "Python value error. Must be List[float]."); - - - return items; -} - -std::vector -ToStringVect(PyObject* value, const std::string& message) -{ - - std::vector items; - if (value == nullptr) - return items; - - - if (PyTuple_Check(value)) - { - for (Py_ssize_t i = 0; i < PyTuple_Size(value); ++i) - { - PyObject* item = PyTuple_GetItem(value, i); - if (PyUnicode_Check(item)) - items.emplace_back(_PyUnicode_AsString(item)); - else - { - PyObject* str = PyObject_Str(item); - items.emplace_back(_PyUnicode_AsString(str)); - Py_XDECREF(str); - } - } - } - - else if (PyList_Check(value)) - { - for (Py_ssize_t i = 0; i < PyList_Size(value); ++i) - { - PyObject* item = PyList_GetItem(value, i); - if (PyUnicode_Check(item)) - items.emplace_back(_PyUnicode_AsString(item)); - else - { - PyObject* str = PyObject_Str(item); - items.emplace_back(_PyUnicode_AsString(str)); - Py_XDECREF(str); - } - } - } - - else - mvThrowPythonError(mvErrorCode::mvWrongType, "Python value error. Must be List[str]."); - - - return items; -} - -mvColor -ToColor(PyObject* value, const std::string& message) -{ - float color[4] = { -1.0f, 0.0f, 0.0f, 1.0f }; - - if (value == nullptr) - return mvColor{ color[0], color[1], color[2], color[3] }; - - if (PyTuple_Check(value)) - { - for (Py_ssize_t i = 0; i < PyTuple_Size(value); ++i) - { - if (i >= 4) - break; - PyObject* item = PyTuple_GetItem(value, i); - if(PyNumber_Check(item)) - color[i] = (float)PyFloat_AsDouble(item)/255.0f; - } - - } - else if (PyList_Check(value)) - { - for (Py_ssize_t i = 0; i < PyList_Size(value); ++i) - { - if (i >= 4) - break; - PyObject* item = PyList_GetItem(value, i); - if (PyNumber_Check(item)) - color[i] = (float)PyFloat_AsDouble(item)/255.0f; - } - } - - return mvColor{ color[0], color[1], color[2], color[3] }; -} - -ImPlotPoint -ToPoint(PyObject* value, const std::string& message) -{ - if (value == nullptr) - return { 0.0, 0.0 }; - - std::vector result = ToDoubleVect(value, message); - - if (result.size() > 1) - return { result[0], result[1] }; - else if (result.size() == 1) - return { result[0], 0.0 }; - else - return { 0.0, 0.0 }; -} - -mvVec2 -ToVec2(PyObject* value, const std::string& message) -{ - if (value == nullptr) - return { 0.0f, 0.0f }; - - std::vector result = ToFloatVect(value, message); - - if (result.size() > 1) - return { result[0], result[1] }; - else if (result.size() == 1) - return { result[0], 0.0f }; - else - return { 0.0f, 0.0f }; -} - -mvVec4 -ToVec4(PyObject* value, const std::string& message) -{ - if (value == nullptr) - return { 0.0f, 0.0f, 0.0f, 0.0f }; - - std::vector result = ToFloatVect(value, message); - - if (result.size() > 3) - return { result[0], result[1], result[2], result[3] }; - else if (result.size() > 2) - return { result[0], result[1], result[2], 0.0f }; - else if (result.size() > 1) - return { result[0], result[1], 0.0f, 0.0f }; - else if (result.size() == 1) - return { result[0], 0.0f, 0.0f, 0.0f }; - else - return { 0.0f, 0.0f, 0.0f, 0.0f }; -} - -std::vector> -ToVectPairString(PyObject* value, const std::string& message) -{ - std::vector> items; - if (value == nullptr) - return items; - - - if (PyTuple_Check(value)) - { - for (Py_ssize_t i = 0; i < PyTuple_Size(value); ++i) - { - PyObject* item = PyTuple_GetItem(value, i); - if (PyTuple_Size(item) == 2) - items.emplace_back(PyUnicode_AsUTF8(PyTuple_GetItem(item, 0)), PyUnicode_AsUTF8(PyTuple_GetItem(item, 1))); - - } - - } - else if (PyList_Check(value)) - { - for (Py_ssize_t i = 0; i < PyList_Size(value); ++i) - { - PyObject* item = PyList_GetItem(value, i); - if (PyList_Size(item) == 2) - items.emplace_back(PyUnicode_AsUTF8(PyList_GetItem(item, 0)), PyUnicode_AsUTF8(PyList_GetItem(item, 1))); - - } - } - - else - mvThrowPythonError(mvErrorCode::mvWrongType, "Python value error. Must be List[List[str, str]]."); - - return items; -} - -std::vector -ToVectVec2(PyObject* value, const std::string& message) -{ - std::vector items; - if (value == nullptr) - return items; - - - if (PyTuple_Check(value)) - { - for (Py_ssize_t i = 0; i < PyTuple_Size(value); ++i) - items.push_back(ToVec2(PyTuple_GetItem(value, i))); - } - else if (PyList_Check(value)) - { - for (Py_ssize_t i = 0; i < PyList_Size(value); ++i) - items.push_back(ToVec2(PyList_GetItem(value, i))); - } - - else - mvThrowPythonError(mvErrorCode::mvWrongType, "Python value error. Must be List[List[int, int]]."); - - return items; -} - -std::pair, std::vector> -ToPairVec(PyObject* value, const std::string& message) -{ - std::pair, std::vector> items; - if (value == nullptr) - return items; - - - if (PyTuple_Check(value)) - { - if (PyTuple_Size(value) != 2) mvThrowPythonError(mvErrorCode::mvNone, message); - items.first = ToFloatVect(PyTuple_GetItem(value, 0), message); - items.second = ToFloatVect(PyTuple_GetItem(value, 1), message); - } - else if (PyList_Check(value)) - { - if (PyList_Size(value) != 2) mvThrowPythonError(mvErrorCode::mvNone, message); - items.first = ToFloatVect(PyList_GetItem(value, 0), message); - items.second = ToFloatVect(PyList_GetItem(value, 1), message); - } - - else - mvThrowPythonError(mvErrorCode::mvWrongType, message); - - return items; -} - -std::vector -ToVectVec4(PyObject* value, const std::string& message) -{ - std::vector items; - if (value == nullptr) - return items; - - - if (PyTuple_Check(value)) - { - for (Py_ssize_t i = 0; i < PyTuple_Size(value); ++i) - items.push_back(ToVec4(PyTuple_GetItem(value, i))); - } - else if (PyList_Check(value)) - { - for (Py_ssize_t i = 0; i < PyList_Size(value); ++i) - items.push_back(ToVec4(PyList_GetItem(value, i))); - } - - else - mvThrowPythonError(mvErrorCode::mvWrongType, message); - - return items; -} - -std::vector> -ToVectInt2(PyObject* value, const std::string& message) -{ - std::vector> items; - if (value == nullptr) - return items; - - - if (PyTuple_Check(value)) - { - for (Py_ssize_t i = 0; i < PyTuple_Size(value); ++i) - { - PyObject* point = PyTuple_GetItem(value, i); - if(PyTuple_Check(point)) - { - if (PyTuple_Size(point) >= 2) { - int x = PyLong_AsLong(PyTuple_GetItem(point, 0)); - int y = PyLong_AsLong(PyTuple_GetItem(point, 1)); - items.emplace_back(x, y); - } - } - else if(PyList_Check(point)) - { - if (PyList_Size(point) >= 2) { - int x = PyLong_AsLong(PyList_GetItem(point, 0)); - int y = PyLong_AsLong(PyList_GetItem(point, 1)); - items.emplace_back(x, y); - } - } - else - items.emplace_back(0, 0); - } - } - - else if (PyList_Check(value)) - { - for (Py_ssize_t i = 0; i < PyList_Size(value); ++i) - { - PyObject* point = PyList_GetItem(value, i); - if(PyTuple_Check(point)) - { - if (PyTuple_Size(point) >= 2) { - int x = PyLong_AsLong(PyTuple_GetItem(point, 0)); - int y = PyLong_AsLong(PyTuple_GetItem(point, 1)); - items.emplace_back(x, y); - } - } - else if(PyList_Check(point)) - { - if (PyList_Size(point) >= 2) { - int x = PyLong_AsLong(PyList_GetItem(point, 0)); - int y = PyLong_AsLong(PyList_GetItem(point, 1)); - items.emplace_back(x, y); - } - } - else - items.emplace_back(0, 0); - } - } - - else - mvThrowPythonError(mvErrorCode::mvWrongType, message); - - return items; - -} - -std::vector> -ToVectVectString(PyObject* value, const std::string& message) -{ - std::vector> items; - if (value == nullptr) - return items; - - - if (PyTuple_Check(value)) - { - for (Py_ssize_t i = 0; i < PyTuple_Size(value); ++i) - items.emplace_back(ToStringVect(PyTuple_GetItem(value, i), message)); - } - - else if (PyList_Check(value)) - { - for (Py_ssize_t i = 0; i < PyList_Size(value); ++i) - items.emplace_back(ToStringVect(PyList_GetItem(value, i), message)); - } - - return items; -} - -std::vector> -ToVectPairStringFloat(PyObject* value, const std::string& message) -{ - std::vector> items; - if (value == nullptr) - return items; - - - if (PyTuple_Check(value)) - { - for (Py_ssize_t i = 0; i < PyTuple_Size(value); ++i) - { - PyObject* item = PyTuple_GetItem(value, i); - if (PyTuple_Size(item) == 2 && PyNumber_Check(PyTuple_GetItem(item, 1))) - items.emplace_back(PyUnicode_AsUTF8(PyTuple_GetItem(item, 0)), (float)PyFloat_AsDouble(PyTuple_GetItem(item, 1))); - - } - - } - else if (PyList_Check(value)) - { - for (Py_ssize_t i = 0; i < PyList_Size(value); ++i) - { - PyObject* item = PyList_GetItem(value, i); - if (PyList_Size(item) == 2 && PyNumber_Check(PyList_GetItem(item, 1))) - items.emplace_back(PyUnicode_AsUTF8(PyList_GetItem(item, 0)), (float)PyFloat_AsDouble(PyList_GetItem(item, 1))); - - } - } - - else - mvThrowPythonError(mvErrorCode::mvWrongType, message); - - return items; -} - -std::vector> -ToVectVectFloat(PyObject* value, const std::string& message) -{ - std::vector> items; - if (value == nullptr) - return items; - - - if (PyTuple_Check(value)) - { - for (Py_ssize_t i = 0; i < PyTuple_Size(value); ++i) - items.emplace_back(ToFloatVect(PyTuple_GetItem(value, i), message)); - } - - else if (PyList_Check(value)) - { - for (Py_ssize_t i = 0; i < PyList_Size(value); ++i) - items.emplace_back(ToFloatVect(PyList_GetItem(value, i), message)); - } - - return items; -} - -std::vector> -ToVectVectInt(PyObject* value, const std::string& message) -{ - std::vector> items; - if (value == nullptr) - return items; - - - if (PyTuple_Check(value)) - { - for (Py_ssize_t i = 0; i < PyTuple_Size(value); ++i) - items.emplace_back(ToIntVect(PyTuple_GetItem(value, i), message)); - } - - else if (PyList_Check(value)) - { - for (Py_ssize_t i = 0; i < PyList_Size(value); ++i) - items.emplace_back(ToIntVect(PyList_GetItem(value, i), message)); - } - - return items; -} - -std::vector> -ToVectVectDouble(PyObject* value, const std::string& message) -{ - std::vector> items; - if (value == nullptr) - return items; - - - if (PyTuple_Check(value)) - { - for (Py_ssize_t i = 0; i < PyTuple_Size(value); ++i) - items.emplace_back(ToDoubleVect(PyTuple_GetItem(value, i), message)); - } - - else if (PyList_Check(value)) - { - for (Py_ssize_t i = 0; i < PyList_Size(value); ++i) - items.emplace_back(ToDoubleVect(PyList_GetItem(value, i), message)); - } - - return items; -} \ No newline at end of file diff --git a/src/mvPythonTypeChecker.cpp b/src/mvPythonTypeChecker.cpp deleted file mode 100644 index 7c377e9da..000000000 --- a/src/mvPythonTypeChecker.cpp +++ /dev/null @@ -1,291 +0,0 @@ -#include "mvPythonTypeChecker.h" -#define PY_SSIZE_T_CLEAN -#include - -bool -isPyObject_Any(PyObject* obj) -{ - return obj != nullptr; -} - -bool -isPyObject_String(PyObject* obj) -{ - if (obj == nullptr) - return false; - - if (PyUnicode_Check(obj)) - return true; - else - { - PyObject* str = PyObject_Str(obj); - if (str == nullptr) - return false; - Py_XDECREF(str); - } - - return true; -} - -bool -isPyObject_Int(PyObject* obj) -{ - if (obj == nullptr) - return false; - - if (!PyNumber_Check(obj)) - return false; - return true; -} - -bool -isPyObject_Float(PyObject* obj) -{ - if (obj == nullptr) - return false; - - if (!PyNumber_Check(obj)) - return false; - return true; -} - -bool -isPyObject_Bool(PyObject* obj) -{ - if (obj == nullptr) - return false; - - if (!PyBool_Check(obj)) - return false; - return true; -} - -bool -isPyObject_StringList(PyObject* obj) -{ - if (obj == nullptr) - return false; - - if (PyTuple_Check(obj)) - { - if (PyTuple_Size(obj) > 1) - { - PyObject* item = PyTuple_GetItem(obj, 0); - if (PyUnicode_Check(item)) - return true; - else - return isPyObject_String(item); - } - - return true; - } - else if (PyList_Check(obj)) - { - if (PyList_Size(obj) > 1) - { - PyObject* item = PyList_GetItem(obj, 0); - if (PyUnicode_Check(item)) - return true; - else - return isPyObject_String(item); - } - - return true; - } - - return false; -} - -bool -isPyObject_ListStringList(PyObject* obj) -{ - if (obj == nullptr) - return false; - - if (PyTuple_Check(obj)) - { - if (PyTuple_Size(obj) > 1) - { - PyObject* item = PyTuple_GetItem(obj, 0); - return isPyObject_StringList(item); - } - - return true; - } - else if (PyList_Check(obj)) - { - if (PyList_Size(obj) > 1) - { - PyObject* item = PyList_GetItem(obj, 0); - return isPyObject_StringList(item); - } - - return true; - } - - return false; -} - -bool -isPyObject_FloatList(PyObject* obj) -{ - if (obj == nullptr) - return false; - - if (PyTuple_Check(obj)) - { - if (PyTuple_Size(obj) > 1) - { - PyObject* item = PyTuple_GetItem(obj, 0); - return isPyObject_Float(item); - } - - return true; - } - else if (PyList_Check(obj)) - { - if (PyList_Size(obj) > 1) - { - PyObject* item = PyList_GetItem(obj, 0); - return isPyObject_Float(item); - } - - return true; - } - - else if (PyObject_CheckBuffer(obj)) - { - return true; - } - - return false; -} - -bool -isPyObject_ListFloatList(PyObject* obj) -{ - if (obj == nullptr) - return false; - - if (PyTuple_Check(obj)) - { - if (PyTuple_Size(obj) > 1) - { - PyObject* item = PyTuple_GetItem(obj, 0); - return isPyObject_FloatList(item); - } - - return true; - } - else if (PyList_Check(obj)) - { - if (PyList_Size(obj) > 1) - { - PyObject* item = PyList_GetItem(obj, 0); - return isPyObject_FloatList(item); - } - - return true; - } - - return false; -} - -bool -isPyObject_IntList(PyObject* obj) -{ - if (obj == nullptr) - return false; - - if (PyTuple_Check(obj)) - { - if (PyTuple_Size(obj) > 1) - { - PyObject* item = PyTuple_GetItem(obj, 0); - return isPyObject_Int(item); - } - - return true; - } - else if (PyList_Check(obj)) - { - if (PyList_Size(obj) > 1) - { - PyObject* item = PyList_GetItem(obj, 0); - return isPyObject_Int(item); - } - - return true; - } - - else if (PyObject_CheckBuffer(obj)) - { - return true; - } - - return false; -} - -bool -isPyObject_ListIntList(PyObject* obj) -{ - if (obj == nullptr) - return false; - - if (PyTuple_Check(obj)) - { - if (PyTuple_Size(obj) > 1) - { - PyObject* item = PyTuple_GetItem(obj, 0); - return isPyObject_IntList(item); - } - - return true; - } - else if (PyList_Check(obj)) - { - if (PyList_Size(obj) > 1) - { - PyObject* item = PyList_GetItem(obj, 0); - return isPyObject_IntList(item); - } - - return true; - } - - return false; -} - -bool -isPyObject_Double(PyObject* obj) -{ - if (obj == nullptr) - return false; - - if (PyFloat_Check(obj)) - return true; - - return false; -} - -bool -isPyObject_Callable(PyObject* obj) -{ - if (obj == nullptr) - return false; - - if (PyCallable_Check(obj)) - return true; - return false; -} - -bool -isPyObject_Dict(PyObject* obj) -{ - if (obj == nullptr) - return false; - - if (PyDict_Check(obj)) - return true; - return false; -} \ No newline at end of file diff --git a/src/mvPythonTypeChecker.h b/src/mvPythonTypeChecker.h deleted file mode 100644 index 43370c5a2..000000000 --- a/src/mvPythonTypeChecker.h +++ /dev/null @@ -1,24 +0,0 @@ -#pragma once - -// forward declare PyObject -// as suggested on the python mailing list -// http://mail.python.org/pipermail/python-dev/2003-August/037601.html -#ifndef PyObject_HEAD -struct _object; -typedef _object PyObject; -#endif - -bool isPyObject_String (PyObject* obj); -bool isPyObject_Int (PyObject* obj); -bool isPyObject_Float (PyObject* obj); -bool isPyObject_Bool (PyObject* obj); -bool isPyObject_StringList (PyObject* obj); -bool isPyObject_ListStringList(PyObject* obj); -bool isPyObject_FloatList (PyObject* obj); -bool isPyObject_ListFloatList (PyObject* obj); -bool isPyObject_IntList (PyObject* obj); -bool isPyObject_ListIntList (PyObject* obj); -bool isPyObject_Double (PyObject* obj); -bool isPyObject_Callable (PyObject* obj); -bool isPyObject_Dict (PyObject* obj); -bool isPyObject_Any (PyObject* obj); \ No newline at end of file diff --git a/src/mvTables.cpp b/src/mvTables.cpp index 396861c2a..355a4db9b 100644 --- a/src/mvTables.cpp +++ b/src/mvTables.cpp @@ -3,8 +3,7 @@ #include "mvCore.h" #include "mvLog.h" #include "mvItemRegistry.h" -#include "mvPyObject.h" -#include "mvPythonExceptions.h" +#include "mvPyUtils.h" #include "mvFontItems.h" #include "mvThemes.h" diff --git a/src/mvTextureItems.cpp b/src/mvTextureItems.cpp index cf3399a02..ac30e8b9d 100644 --- a/src/mvTextureItems.cpp +++ b/src/mvTextureItems.cpp @@ -1,7 +1,6 @@ #include "mvTextureItems.h" -#include "mvPythonExceptions.h" +#include "mvPyUtils.h" #include "mvLog.h" -#include "mvGlobalIntepreterLock.h" #include "mvUtilities.h" mvTextureRegistry::mvTextureRegistry(mvUUID uuid) diff --git a/src/mvThemes.cpp b/src/mvThemes.cpp index daed6391c..a4fc28f51 100644 --- a/src/mvThemes.cpp +++ b/src/mvThemes.cpp @@ -1,6 +1,6 @@ #include "mvThemes.h" #include "mvLog.h" -#include "mvPythonExceptions.h" +#include "mvPyUtils.h" #include #include diff --git a/src/mvToolManager.cpp b/src/mvToolManager.cpp index 276d86f46..c57a7b29a 100644 --- a/src/mvToolManager.cpp +++ b/src/mvToolManager.cpp @@ -1,5 +1,5 @@ #include "mvToolManager.h" -#include "mvPythonTranslator.h" +#include "mvPyUtils.h" #include "mvAboutWindow.h" #include "mvDocWindow.h" #include "mvMetricsWindow.h" diff --git a/src/mvUtilities_apple.mm b/src/mvUtilities_apple.mm index bb1d92b8c..79f7c4205 100644 --- a/src/mvUtilities_apple.mm +++ b/src/mvUtilities_apple.mm @@ -13,7 +13,7 @@ #include #include #include "mvAppleSpecifics.h" -#include "mvPythonExceptions.h" +#include "mvPyUtils.h" // this is necessary to keep objective-c's reference counts // from reaching 0. diff --git a/src/mvUtilities_linux.cpp b/src/mvUtilities_linux.cpp index 517be7656..b26ef1ff6 100644 --- a/src/mvUtilities_linux.cpp +++ b/src/mvUtilities_linux.cpp @@ -14,7 +14,7 @@ #include "mvContext.h" #include "mvLinuxSpecifics.h" #include "mvViewport.h" -#include "mvPythonExceptions.h" +#include "mvPyUtils.h" #include "mvCustomTypes.h" static std::unordered_map PBO_ids; diff --git a/src/mvValues.cpp b/src/mvValues.cpp index 0ecd3d979..686a76e4f 100644 --- a/src/mvValues.cpp +++ b/src/mvValues.cpp @@ -3,7 +3,7 @@ #include "mvContext.h" #include "dearpygui.h" #include -#include "mvPythonExceptions.h" +#include "mvPyUtils.h" PyObject* mvBoolValue::getPyValue() {