Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
The table of contents is too big for display.
Diff view
Diff view
  •  
  •  
  •  
182 changes: 182 additions & 0 deletions InternalAPI/MSPyCommon.h
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,8 @@
#pragma once
#include "ScriptEngineManager.h"

using namespace std;

#define _CRT_SECURE_NO_WARNINGS

#define __EXPAND(x) x
Expand Down Expand Up @@ -45,17 +47,128 @@ struct mspydelete {

// Smart pointer declaration
PYBIND11_DECLARE_HOLDER_TYPE(RefCountedBaseT, RefCountedPtr<RefCountedBaseT>, false);
PYBIND11_DECLARE_HOLDER_TYPE(T, TempObjectOwner<T>, false);

// Non-delete smart pointer
#define DEFINE_NODELETE_HOLDER_TYPE(type) using type##Ptr = std::unique_ptr<type, py::nodelete>

namespace std {
template <typename _Ty1, typename _Ty2>
struct tuple_size<Bentley::Bstdcxx::bpair<_Ty1, _Ty2>> : std::integral_constant<size_t, 2> {};

template<class _Ty1,class _Ty2>
struct tuple_element<0, Bentley::Bstdcxx::bpair<_Ty1, _Ty2> >
{ // struct to determine type of element 0 in pair
typedef _Ty1 type;
};

template<class _Ty1, class _Ty2>
struct tuple_element<1, Bentley::Bstdcxx::bpair<_Ty1, _Ty2> >
{ // struct to determine type of element 1 in pair
typedef _Ty2 type;
};

template <typename _Rtype, typename _Ty1, typename _Ty2>
constexpr _Rtype _Pair_get(Bentley::Bstdcxx::bpair<_Ty1, _Ty2>& _Pr, std::integral_constant<size_t, 0>) noexcept {
return _Pr.first;
}

template <typename _Rtype, typename _Ty1, typename _Ty2>
constexpr _Rtype _Pair_get(Bentley::Bstdcxx::bpair<_Ty1, _Ty2>& _Pr, std::integral_constant<size_t, 1>) noexcept {
return _Pr.second;
}

template<size_t _Idx,
class _Ty1,
class _Ty2> inline
constexpr typename tuple_element<_Idx, Bentley::Bstdcxx::bpair<_Ty1, _Ty2> >::type&
get (Bentley::Bstdcxx::bpair<_Ty1, _Ty2>& _Pr) noexcept
{ // get reference to element at _Idx in pair _Pr
typedef typename tuple_element<_Idx, pair<_Ty1, _Ty2> >::type& _Rtype;
return (_Pair_get<_Rtype>(_Pr, integral_constant<size_t, _Idx>()));
};

template<class _Ty1,
class _Ty2> inline
constexpr _Ty1& get(Bentley::Bstdcxx::bpair<_Ty1, _Ty2>& _Pr) noexcept
{ // get reference to element _Ty1 in pair _Pr
return (_STD get<0>(_Pr));
};

template<class _Ty2,
class _Ty1> inline
constexpr _Ty2& get(Bentley::Bstdcxx::bpair<_Ty1, _Ty2>& _Pr) noexcept
{ // get reference to element _Ty2 in pair _Pr
return (_STD get<1>(_Pr));
};

template<size_t _Idx,
class _Ty1,
class _Ty2> inline
constexpr typename tuple_element<_Idx, Bentley::Bstdcxx::bpair<_Ty1, _Ty2> >::type&&
get (Bentley::Bstdcxx::bpair<_Ty1, _Ty2>&& _Pr) noexcept
{ // get rvalue reference to element at _Idx in pair _Pr
typedef typename tuple_element<_Idx, pair<_Ty1, _Ty2> >::type&& _RRtype;
return (_STD forward<_RRtype>(_STD get<_Idx>(_Pr)));
};

template<class _Ty1,
class _Ty2> inline
constexpr _Ty1&& get(Bentley::Bstdcxx::bpair<_Ty1, _Ty2>&& _Pr) noexcept
{ // get rvalue reference to element _Ty1 in pair _Pr
return (_STD get<0>(_STD move(_Pr)));
};

template<class _Ty2,
class _Ty1> inline
constexpr _Ty2&& get(Bentley::Bstdcxx::bpair<_Ty1, _Ty2>&& _Pr) noexcept
{ // get rvalue reference to element _Ty2 in pair _Pr
return (_STD get<1>(_STD move(_Pr)));
};

template<size_t _Idx,
class _Ty1,
class _Ty2> inline
constexpr const typename tuple_element<_Idx, Bentley::Bstdcxx::bpair<_Ty1, _Ty2> >::type&
get (const Bentley::Bstdcxx::bpair<_Ty1, _Ty2>& _Pr) noexcept
{ // get const reference to element at _Idx in pair _Pr
typedef const typename tuple_element<_Idx, pair<_Ty1, _Ty2> >::type&
_Ctype;
return (_Pair_get<_Ctype>(_Pr, integral_constant<size_t, _Idx>()));
};

template<class _Ty1,
class _Ty2> inline
constexpr const _Ty1& get(const Bentley::Bstdcxx::bpair<_Ty1, _Ty2>& _Pr) noexcept
{ // get const reference to element _Ty1 in pair _Pr
return (_STD get<0>(_Pr));
}

template<class _Ty2,
class _Ty1> inline
constexpr const _Ty2& get(const Bentley::Bstdcxx::bpair<_Ty1, _Ty2>& _Pr) noexcept
{ // get const reference to element _Ty2 in pair _Pr
return (_STD get<1>(_Pr));
}
}

namespace PYBIND11_NAMESPACE {
namespace detail {
template <typename T>
struct type_caster<boost::optional<T>> : optional_caster<boost::optional<T>> {};

template <typename T1, typename T2>
class type_caster<Bentley::Bstdcxx::bpair<T1, T2>> : public tuple_caster<Bentley::Bstdcxx::bpair, T1, T2> {};

template <typename Key, typename Compare, typename Alloc>
struct type_caster<Bentley::bset<Key, Compare, 32, Alloc>>
: set_caster<Bentley::bset<Key, Compare, 32, Alloc>, Key> {};
}
}




// PYBIND11_OVERRIDE with exception capture and has return value.
#define PYBIND11_OVERRIDE_EXR(ret_type, cname, fn, error, ...) \
try \
Expand Down Expand Up @@ -215,3 +328,72 @@ py::class_<bvector<ValueType>, holder_type> bind_PointerVector(py::handle scope,

return cls;
}

// Convert Python list to an existing C++ array
template <typename arrayType, typename itemType>
void ConvertPyListToCppArray(py::list const& pyList, arrayType& cppArray)
{
cppArray.clear();
for (auto item : pyList)
{
if (!py::isinstance<itemType>(item))
{
throw std::invalid_argument("All items in the list must be of the correct item type");
}
auto cppItem = item.cast<itemType>();
cppArray.push_back(cppItem);
}
}

// Convert Python list to a new C++ array
template <typename arrayType, typename itemType>
arrayType ConvertPyListToCppArray(py::list const& pyList)
{
arrayType cppArray;
for (auto item : pyList)
{
if (!py::isinstance<itemType>(item))
{
throw std::invalid_argument("All items in the list must be of the correct item type");
}
auto cppItem = item.cast<itemType>();
cppArray.push_back(cppItem);
}
return cppArray;
}

// Convert C++ array to an existing Python list
template <typename arrayType, typename itemType>
void ConvertCppArrayToPyList(py::list& pyList, arrayType const& cppArray)
{
pyList.attr("clear")();
for (const itemType& item : cppArray)
{
pyList.append(py::cast(item));
}
}

// Convert C++ array to a new Python list
template <typename arrayType, typename itemType>
py::list ConvertCppArrayToPyList(arrayType const& cppArray)
{
py::list pyList;
for (const itemType& item : cppArray)
{
pyList.append(py::cast(item));
}
return pyList;
}

// Macros
#define CONVERT_PYLIST_TO_CPPARRAY(pyList, cppArray, cppArrayType, cppItemType) \
ConvertPyListToCppArray<cppArrayType, cppItemType>(pyList, cppArray);

#define CONVERT_PYLIST_TO_NEW_CPPARRAY(pyList, cppArray, cppArrayType, cppItemType) \
cppArrayType cppArray = ConvertPyListToCppArray<cppArrayType, cppItemType>(pyList);

#define CONVERT_CPPARRAY_TO_PYLIST(pyList, cppArray, cppArrayType, cppItemType) \
ConvertCppArrayToPyList<cppArrayType, cppItemType>(pyList, cppArray);

#define CONVERT_CPPARRAY_TO_NEW_PYLIST(pyList, cppArray, cppArrayType, cppItemType) \
py::list pyList = ConvertCppArrayToPyList<cppArrayType, cppItemType>(cppArray);
1 change: 1 addition & 0 deletions InternalAPI/OpqueTypes_Bentley.h
Original file line number Diff line number Diff line change
Expand Up @@ -30,3 +30,4 @@ DEFINE_BVECTOR_TYPE(Utf8String, Utf8StringArray);
// Commonly used bmap
DEFINE_BMAP_TYPE(WString, WString, WStringWStringMap);
DEFINE_BMAP_TYPE(WString, WCharCP, WStringWCharMap);
DEFINE_BMAP_TYPE(int, int, IntIntMap);
1 change: 1 addition & 0 deletions InternalAPI/OpqueTypes_Geom.h
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ DEFINE_BVECTOR_TYPE(DPoint3dArray, DPoint3dVecArray);
DEFINE_BVECTOR_TYPE(DPoint3dVecArray, DPoint3dVecVecArray);
DEFINE_BVECTOR_TYPE(DVec3dArray, DVec3dVecArray);
DEFINE_BVECTOR_TYPE(ICurvePrimitivePtr, ICurvePrimitiveArray);
DEFINE_BVECTOR_TYPE(CurvePrimitivePtrPair, CurvePrimitivePtrPairArray);
DEFINE_BVECTOR_TYPE(DSegment1d, DSegment1dArray);
DEFINE_BVECTOR_TYPE(DSegment3d, DSegment3dArray);
DEFINE_BVECTOR_TYPE(CurveLocationDetail, CurveLocationDetailArray);
Expand Down
3 changes: 2 additions & 1 deletion MSPythonCore.mke
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
#--------------------------------------------------------------------------------------
appName = MSPythonCore


%if defined (BSIBUILD)
MSPythonSrc = $(SrcRoot)MSPython/
%else
Expand Down Expand Up @@ -41,7 +42,7 @@ MultiCompileDepends = $(_MakeFileSpec)
PchCompiland = $(baseDir)MSPythonPCH.cpp
PchOutputDir = $(o)
PchArgumentsDepends = $(MultiCompileDepends)
PchExtraOptions + -Zm170 -wd4456 -wd4457 -wd4459 -wd4311 -wd4312 -wd4302 -wd4471
PchExtraOptions + -Zm170 -wd4456 -wd4457 -wd4459 -wd4311 -wd4312 -wd4302 -wd4471 -wd4653 -wd4652 -wd4651

%include $(MSPythonSrc)/build/publicSDK/PreCompileHeader.mki

Expand Down
62 changes: 56 additions & 6 deletions MSPythonCore/ScriptEngineManager/source/MSPythonEngine.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -733,12 +733,14 @@ ScriptValuePtr PythonScriptEngine::eval(WCharCP expr, ScriptContext* global, Scr
ScriptEngineManager::Get().ClearException();
try
{
mdlErrno = 0;
py::object obj = py::eval(py::cast(expr), globalDict, py::len(localDict) > 0 ? localDict : py::object ());
outVal = new PythonScriptValue(obj);
}
catch (py::error_already_set& err)
{
ScriptEngineManager::Get().InjectException(err);
mdlErrno = MDLERR_PYTHONEXECUTIONERROR;
}

m_engineProcessing = false;
Expand Down Expand Up @@ -783,16 +785,56 @@ void PythonScriptEngine::exec(WCharCP stms, WCharCP funcName, ScriptContext* glo
m_engineProcessing = true;
try
{
mdlErrno = 0;
py::exec(py::cast(stms), globalDict, py::len(localDict) > 0 ? localDict : py::object ());
}
catch (py::error_already_set& err)
{
ScriptEngineManager::Get().InjectException(err);
mdlErrno = MDLERR_PYTHONEXECUTIONERROR;
}
m_engineProcessing = false;

}


/*---------------------------------------------------------------------------------**//***
@bsimethod 3/2025
+---------------+---------------+---------------+---------------+---------------+------*/
static bool isPydLoadingFailed(const std::string& nameModule)
{
auto& internals = py::detail::get_internals();
auto& registered_types_cpp = internals.registered_types_cpp;

for (const auto& item : registered_types_cpp)
{
std::string name = item.second->type->tp_name;
if (name.find(nameModule) != std::string::npos)
{
py::module_ sys = py::module_::import("sys");
if (sys.attr("modules").contains(nameModule))
return false; //loaded successfully
else
return true; //failed to load
}
}

return false; // not found
}

/*---------------------------------------------------------------------------------**//***
@bsimethod 3/2025
+---------------+---------------+---------------+---------------+---------------+------*/
static bool allPydsLoadedSuc()
{
if (isPydLoadingFailed("MSPyBentley") || isPydLoadingFailed("MSPyBentleyGeom") ||
isPydLoadingFailed("MSPyECObjects") || isPydLoadingFailed("MSPyDgnPlatform") ||
isPydLoadingFailed("MSPyDgnView") || isPydLoadingFailed("MSPyMstnPlatform"))
return false;

return true;
}

/*---------------------------------------------------------------------------------**//***
@bsimethod 12/2024
+---------------+---------------+---------------+---------------+---------------+------*/
Expand All @@ -808,6 +850,10 @@ static void getCachedTypes(std::unordered_map<std::type_index, std::string>& bef
+---------------+---------------+---------------+---------------+---------------+------*/
static void removeCachedtypes(const std::unordered_map<std::type_index, std::string>& before_type_cache)
{
if (allPydsLoadedSuc())
return;

//TODO: call py::finalize_interpreter()&py::initialize_interpreter() to restart the python interpreter
auto& internals = py::detail::get_internals();
for (auto it = internals.registered_types_cpp.begin(); it != internals.registered_types_cpp.end();)
{
Expand Down Expand Up @@ -849,7 +895,7 @@ void PythonScriptEngine::eval_file(WCharCP scriptFile, WCharCP funcName, ScriptC
auto pyLocalDict = dynamic_cast<PythonScriptContext*>(localCtx.get());
if (nullptr != pyLocalDict)
localDict = pyLocalDict->m_dict;

m_engineProcessing = true;

// The cache of types registered by pybind11 before running the script
Expand All @@ -861,18 +907,21 @@ void PythonScriptEngine::eval_file(WCharCP scriptFile, WCharCP funcName, ScriptC
{
try
{
// Run file, Python returns errors if the local dictionary is empty
mdlErrno = 0;
// Python returns errors if the local dictionary is empty
py::eval_file(py::cast(scriptFile), globalDict, py::len(localDict) > 0 ? localDict : py::object ());
}
catch (py::error_already_set& e)
{
removeCachedtypes(before_type_cache);
ScriptEngineManager::Get().InjectError( e.what ());
mdlErrno = MDLERR_PYTHONEXECUTIONERROR;
removeCachedtypes(before_type_cache);
}
catch (std::exception& err)
{
removeCachedtypes(before_type_cache);
ScriptEngineManager::Get().InjectException(err);
mdlErrno = MDLERR_PYTHONEXECUTIONERROR;
removeCachedtypes(before_type_cache);
}
}
else // User want to run a function inside given module
Expand All @@ -895,14 +944,15 @@ void PythonScriptEngine::eval_file(WCharCP scriptFile, WCharCP funcName, ScriptC
WString function(funcName);

function.append (L" ()");

mdlErrno = 0;
py::exec(py::cast(function.c_str ()) ,globalDict, localDict);

}
catch (std::exception& err)
{
removeCachedtypes(before_type_cache);
ScriptEngineManager::Get().InjectException(err);
mdlErrno = MDLERR_PYTHONEXECUTIONERROR;
removeCachedtypes(before_type_cache);
}
}
m_engineProcessing = false;
Expand Down
Loading