//====================================================================================================================== // // This file is part of waLBerla. waLBerla is free software: you can // redistribute it and/or modify it under the terms of the GNU General Public // License as published by the Free Software Foundation, either version 3 of // the License, or (at your option) any later version. // // waLBerla is distributed in the hope that it will be useful, but WITHOUT // ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or // FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License // for more details. // // You should have received a copy of the GNU General Public License along // with waLBerla (see COPYING.txt). If not, see <http://www.gnu.org/licenses/>. // //! \file PythonCallback.cpp //! \ingroup python_coupling //! \author Martin Bauer <martin.bauer@fau.de> //! \author Markus Holzer <markus.holzer@fau.de> // //====================================================================================================================== #include "PythonCallback.h" #include "DictWrapper.h" #include "core/logging/all.h" #ifdef WALBERLA_BUILD_WITH_PYTHON #include "Manager.h" #include "core/Abort.h" #include "core/Filesystem.h" #include "pybind11/eval.h" namespace walberla { namespace python_coupling { static py::object importModuleOrFileInternal( const std::string & fileOrModuleName, const std::vector< std::string > & argv ) { auto manager = python_coupling::Manager::instance(); manager->triggerInitialization(); namespace py = pybind11; std::string moduleName = fileOrModuleName; std::stringstream code; code << "import sys" << "\n" ; code << "sys.argv = [ "; for( auto argStrIt = argv.begin(); argStrIt != argv.end(); ++argStrIt ) code << "'" << *argStrIt << "',"; code << "] \n"; filesystem::path path ( fileOrModuleName ); path = filesystem::absolute( path ); if ( path.extension() == ".py" ) { moduleName = path.stem().string(); if ( ! path.parent_path().empty() ) { std::string p = filesystem::canonical(path.parent_path()).string(); code << "sys.path.append( r'" << p << "')" << "\n"; } } py::exec( code.str().c_str(), py::module::import("__main__").attr("__dict__") ); try { return py::module::import( moduleName.c_str() ); } catch ( py::error_already_set &e) { throw py::value_error(e.what()); } } void importModuleOrFile( const std::string & fileOrModuleName, const std::vector< std::string > & argv ) { importModuleOrFileInternal( fileOrModuleName, argv ); } // initializes invalid/empty callback PythonCallback::PythonCallback() : exposedVars_( new DictWrapper() ), callbackDict_( new DictWrapper() ) { Manager::instance()->triggerInitialization(); callbackDict_->dict() = py::dict(); } PythonCallback::PythonCallback( const std::string & fileOrModuleName, const std::string & functionName, const std::vector<std::string> & argv ) : functionName_( functionName ) { Manager::instance()->triggerInitialization(); exposedVars_ = make_shared<DictWrapper>(); callbackDict_ = make_shared<DictWrapper>(); namespace py = pybind11; // Add empty callbacks module importModuleOrFileInternal( fileOrModuleName, argv ); py::object callbackModule = py::module::import( "walberla_cpp.callbacks"); callbackDict_->dict() = py::dict( callbackModule.attr( "__dict__" ) ); } PythonCallback::PythonCallback( const std::string & functionName ) : functionName_( functionName ) { Manager::instance()->triggerInitialization(); exposedVars_ = make_shared<DictWrapper>(); callbackDict_ = make_shared<DictWrapper>(); // Add empty callbacks module py::object callbackModule = py::module::import( "walberla_cpp.callbacks"); callbackDict_->dict() = py::dict( callbackModule.attr( "__dict__" ) ); } bool PythonCallback::isCallable() const { return callbackDict_->dict().contains( functionName_ ); } void PythonCallback::operator() () { if ( ! isCallable() ) WALBERLA_ABORT_NO_DEBUG_INFO( "Could not call python function '" << functionName_ << "'. " << "Did you forget to set the callback function?" ) namespace py = pybind11; try { py::object function = callbackDict_->dict()[ functionName_.c_str() ]; py::object returnVal; returnVal = function( *py::tuple(), **(exposedVars_->dict() ) ); exposedVars_->dict()["returnValue"] = returnVal; } catch ( py::error_already_set &e ) { throw py::value_error(e.what()); } } } // namespace python_coupling } // namespace walberla #else namespace walberla { namespace python_coupling { void importModuleOrFile( const std::string &, const std::vector< std::string > & ) { } PythonCallback::PythonCallback( const std::string & functionName ) : functionName_( functionName ), exposedVars_( new DictWrapper() ), callbackDict_( new DictWrapper() ) {} PythonCallback::PythonCallback( const std::string & functionName, const std::string & , const std::vector<std::string> & ) : functionName_( functionName ), exposedVars_( new DictWrapper() ), callbackDict_( new DictWrapper() ) {} bool PythonCallback::isCallable() const { return false; } void PythonCallback::operator() () { } } // namespace python_coupling } // namespace walberla #endif