diff --git a/src/Plugins/SimplnxCore/CMakeLists.txt b/src/Plugins/SimplnxCore/CMakeLists.txt index 9eadba5950..8db50a8039 100644 --- a/src/Plugins/SimplnxCore/CMakeLists.txt +++ b/src/Plugins/SimplnxCore/CMakeLists.txt @@ -354,7 +354,6 @@ string(HEX ${PYTHON_FILTER_TEMPLATE} PYTHON_FILTER_TEMPLATE) string(REGEX REPLACE "([0-9a-f][0-9a-f])" "0x\\0," PYTHON_FILTER_TEMPLATE ${PYTHON_FILTER_TEMPLATE}) string(APPEND PYTHON_FILTER_TEMPLATE "0x00") - file(READ "${${PLUGIN_NAME}_SOURCE_DIR}/src/${PLUGIN_NAME}/utils/PythonPluginInitTemplate.py" PYTHON_PLUGIN_INIT_TEMPLATE) string(HEX ${PYTHON_PLUGIN_INIT_TEMPLATE} PYTHON_PLUGIN_INIT_TEMPLATE) string(REGEX REPLACE "([0-9a-f][0-9a-f])" "0x\\0," PYTHON_PLUGIN_INIT_TEMPLATE ${PYTHON_PLUGIN_INIT_TEMPLATE}) @@ -365,11 +364,22 @@ string(HEX ${PYTHON_PLUGIN_TEMPLATE} PYTHON_PLUGIN_TEMPLATE) string(REGEX REPLACE "([0-9a-f][0-9a-f])" "0x\\0," PYTHON_PLUGIN_TEMPLATE ${PYTHON_PLUGIN_TEMPLATE}) string(APPEND PYTHON_PLUGIN_TEMPLATE "0x00") +if(WINDOWS) + file(READ "${${PLUGIN_NAME}_SOURCE_DIR}/src/${PLUGIN_NAME}/utils/PythonPluginTemplate.bat" PYTHON_PLUGIN_TEMPLATE_BAT) + string(HEX ${PYTHON_PLUGIN_TEMPLATE_BAT} PYTHON_PLUGIN_TEMPLATE_BAT) + string(REGEX REPLACE "([0-9a-f][0-9a-f])" "0x\\0," PYTHON_PLUGIN_TEMPLATE_BAT ${PYTHON_PLUGIN_TEMPLATE_BAT}) + string(APPEND PYTHON_PLUGIN_TEMPLATE_BAT "0x00") +else() + file(READ "${${PLUGIN_NAME}_SOURCE_DIR}/src/${PLUGIN_NAME}/utils/PythonPluginTemplate.sh" PYTHON_PLUGIN_TEMPLATE_BAT) + string(HEX ${PYTHON_PLUGIN_TEMPLATE_BAT} PYTHON_PLUGIN_TEMPLATE_BAT) + string(REGEX REPLACE "([0-9a-f][0-9a-f])" "0x\\0," PYTHON_PLUGIN_TEMPLATE_BAT ${PYTHON_PLUGIN_TEMPLATE_BAT}) + string(APPEND PYTHON_PLUGIN_TEMPLATE_BAT "0x00") +endif() cmpConfigureFileWithMD5Check(CONFIGURED_TEMPLATE_PATH "${${PLUGIN_NAME}_SOURCE_DIR}/src/${PLUGIN_NAME}/utils/PythonPluginSourceTemplate.in.hpp" - GENERATED_FILE_PATH "${${PLUGIN_NAME}_BINARY_DIR}/generated/${PLUGIN_NAME}/utils/PythonPluginSourceTemplate.hpp") + GENERATED_FILE_PATH "${${PLUGIN_NAME}_BINARY_DIR}/generated/${PLUGIN_NAME}/utils/PythonPluginSourceTemplate.hpp") -#------------------------------------------------------------------------------ + #------------------------------------------------------------------------------ # If there are additional include directories that are needed for this plugin # you can use the target_include_directories(.....) cmake call # target_include_directories(${PLUGIN_NAME} diff --git a/src/Plugins/SimplnxCore/src/SimplnxCore/Filters/Algorithms/GeneratePythonSkeleton.cpp b/src/Plugins/SimplnxCore/src/SimplnxCore/Filters/Algorithms/GeneratePythonSkeleton.cpp index 3aabb40867..f434961b4d 100644 --- a/src/Plugins/SimplnxCore/src/SimplnxCore/Filters/Algorithms/GeneratePythonSkeleton.cpp +++ b/src/Plugins/SimplnxCore/src/SimplnxCore/Filters/Algorithms/GeneratePythonSkeleton.cpp @@ -35,6 +35,7 @@ Result<> GeneratePythonSkeleton::operator()() } else { - return nx::core::WritePythonPluginFiles(m_InputValues->pluginOutputDir, m_InputValues->pluginName, m_InputValues->pluginName, "Description", m_InputValues->filterNames); + return nx::core::WritePythonPluginFiles(m_InputValues->pluginOutputDir, m_InputValues->pluginName, m_InputValues->pluginName, "Description", m_InputValues->filterNames, + m_InputValues->createBatchShellScript, m_InputValues->anacondaEnvName); } } diff --git a/src/Plugins/SimplnxCore/src/SimplnxCore/Filters/Algorithms/GeneratePythonSkeleton.hpp b/src/Plugins/SimplnxCore/src/SimplnxCore/Filters/Algorithms/GeneratePythonSkeleton.hpp index cc12e92604..12cdc5072b 100644 --- a/src/Plugins/SimplnxCore/src/SimplnxCore/Filters/Algorithms/GeneratePythonSkeleton.hpp +++ b/src/Plugins/SimplnxCore/src/SimplnxCore/Filters/Algorithms/GeneratePythonSkeleton.hpp @@ -20,6 +20,8 @@ struct SIMPLNXCORE_EXPORT GeneratePythonSkeletonInputValues std::string pluginName; std::string pluginHumanName; std::string filterNames; + bool createBatchShellScript; + std::string anacondaEnvName; }; /** diff --git a/src/Plugins/SimplnxCore/src/SimplnxCore/Filters/GeneratePythonSkeletonFilter.cpp b/src/Plugins/SimplnxCore/src/SimplnxCore/Filters/GeneratePythonSkeletonFilter.cpp index 2a0dffd49d..10bc6555e3 100644 --- a/src/Plugins/SimplnxCore/src/SimplnxCore/Filters/GeneratePythonSkeletonFilter.cpp +++ b/src/Plugins/SimplnxCore/src/SimplnxCore/Filters/GeneratePythonSkeletonFilter.cpp @@ -66,11 +66,15 @@ Parameters GeneratePythonSkeletonFilter::parameters() const params.insert( std::make_unique(k_PluginFilterNames, "Filter Names (comma-separated)", "The names of filters that will be created, separated by commas (,).", "FirstFilter,SecondFilter")); + params.insertLinkableParameter( + std::make_unique(k_CreateBatchFile_Key, "Create Anaconda Init Batch/Shell Script", "Generates a script file that can be used to export needed environment variables", false)); + params.insert(std::make_unique(k_AnacondaEnvName_Key, "Anaconda Environment Name", "The name of the Anaconda environment.", "nxpython")); + params.linkParameters(k_UseExistingPlugin_Key, k_PluginName_Key, false); params.linkParameters(k_UseExistingPlugin_Key, k_PluginHumanName_Key, false); params.linkParameters(k_UseExistingPlugin_Key, k_PluginOutputDirectory_Key, false); params.linkParameters(k_UseExistingPlugin_Key, k_PluginInputDirectory_Key, true); - + params.linkParameters(k_CreateBatchFile_Key, k_AnacondaEnvName_Key, true); return params; } @@ -135,6 +139,8 @@ Result<> GeneratePythonSkeletonFilter::executeImpl(DataStructure& dataStructure, inputValues.pluginName = filterArgs.value(k_PluginName_Key); inputValues.pluginHumanName = filterArgs.value(k_PluginHumanName_Key); inputValues.filterNames = filterArgs.value(k_PluginFilterNames); + inputValues.createBatchShellScript = filterArgs.value(k_CreateBatchFile_Key); + inputValues.anacondaEnvName = filterArgs.value(k_AnacondaEnvName_Key); return GeneratePythonSkeleton(dataStructure, messageHandler, shouldCancel, &inputValues)(); } diff --git a/src/Plugins/SimplnxCore/src/SimplnxCore/Filters/GeneratePythonSkeletonFilter.hpp b/src/Plugins/SimplnxCore/src/SimplnxCore/Filters/GeneratePythonSkeletonFilter.hpp index 756df2d94b..1e125394bf 100644 --- a/src/Plugins/SimplnxCore/src/SimplnxCore/Filters/GeneratePythonSkeletonFilter.hpp +++ b/src/Plugins/SimplnxCore/src/SimplnxCore/Filters/GeneratePythonSkeletonFilter.hpp @@ -29,7 +29,8 @@ class SIMPLNXCORE_EXPORT GeneratePythonSkeletonFilter : public IFilter static inline constexpr StringLiteral k_PluginHumanName_Key = "plugin_human_name"; static inline constexpr StringLiteral k_PluginInputDirectory_Key = "plugin_input_directory"; static inline constexpr StringLiteral k_PluginOutputDirectory_Key = "plugin_output_directory"; - + static inline constexpr StringLiteral k_CreateBatchFile_Key = "create_batch_shell_script"; + static inline constexpr StringLiteral k_AnacondaEnvName_Key = "anaconda_env_name"; static inline constexpr StringLiteral k_PluginFilterNames = "filter_names"; /** diff --git a/src/Plugins/SimplnxCore/src/SimplnxCore/utils/PythonFilterTemplate.py b/src/Plugins/SimplnxCore/src/SimplnxCore/utils/PythonFilterTemplate.py index 880aaebfe6..1f1cc848fa 100644 --- a/src/Plugins/SimplnxCore/src/SimplnxCore/utils/PythonFilterTemplate.py +++ b/src/Plugins/SimplnxCore/src/SimplnxCore/utils/PythonFilterTemplate.py @@ -8,6 +8,9 @@ class #PYTHON_FILTER_NAME#: """ TEST_KEY = 'test' +# ----------------------------------------------------------------------------- +# These methods should not be edited +# ----------------------------------------------------------------------------- def uuid(self) -> nx.Uuid: """This returns the UUID of the filter. Each filter has a unique UUID value :return: The Filter's Uuid value @@ -15,13 +18,6 @@ def uuid(self) -> nx.Uuid: """ return nx.Uuid('#PYTHON_FILTER_UUID#') - def human_name(self) -> str: - """This returns the name of the filter as a user of DREAM3DNX would see it - :return: The filter's human name - :rtype: string - """ - return '#PYTHON_FILTER_HUMAN_NAME#' - def class_name(self) -> str: """The returns the name of the class that implements the filter :return: The name of the implementation class @@ -36,13 +32,6 @@ def name(self) -> str: """ return '#PYTHON_FILTER_NAME#' - def default_tags(self) -> List[str]: - """This returns the default tags for this filter - :return: The default tags for the filter - :rtype: list - """ - return ['python'] - def clone(self): """Clones the filter :return: A new instance of the filter @@ -50,6 +39,27 @@ def clone(self): """ return #PYTHON_FILTER_NAME#() +# ----------------------------------------------------------------------------- +# These methods CAN (and probably should) be updated. For instance, the +# human_name() is what users of the filter will see in the DREAM3D-NX GUI. You +# might want to consider putting spaces between workd, using proper capitalization +# and putting "(Python)" at the end of the name (or beginning if you want the +# filter list to group your filters togther) +# ----------------------------------------------------------------------------- + def human_name(self) -> str: + """This returns the name of the filter as a user of DREAM3DNX would see it + :return: The filter's human name + :rtype: string + """ + return '#PYTHON_FILTER_HUMAN_NAME# (Python)' + + def default_tags(self) -> List[str]: + """This returns the default tags for this filter + :return: The default tags for the filter + :rtype: list + """ + return ['python', '#PYTHON_FILTER_HUMAN_NAME#'] + def parameters(self) -> nx.Parameters: """This function defines the parameters that are needed by the filter. Parameters collect the values from the user or through a pipeline file. diff --git a/src/Plugins/SimplnxCore/src/SimplnxCore/utils/PythonPluginSourceTemplate.in.hpp b/src/Plugins/SimplnxCore/src/SimplnxCore/utils/PythonPluginSourceTemplate.in.hpp index 727c4f5ac6..e73e41ec6b 100644 --- a/src/Plugins/SimplnxCore/src/SimplnxCore/utils/PythonPluginSourceTemplate.in.hpp +++ b/src/Plugins/SimplnxCore/src/SimplnxCore/utils/PythonPluginSourceTemplate.in.hpp @@ -37,4 +37,13 @@ inline const std::string PluginInitPythonFile() return {k_PluginInitPythonFileCharArray}; } +// clang-format off +static const char k_PluginBatchFileCharArray[] = {@PYTHON_PLUGIN_TEMPLATE_BAT@}; +// clang-format on + +inline const std::string PluginBatchFile() +{ + return {k_PluginBatchFileCharArray}; +} + }; // namespace nx::core \ No newline at end of file diff --git a/src/Plugins/SimplnxCore/src/SimplnxCore/utils/PythonPluginTemplate.bat b/src/Plugins/SimplnxCore/src/SimplnxCore/utils/PythonPluginTemplate.bat new file mode 100644 index 0000000000..374c5147b5 --- /dev/null +++ b/src/Plugins/SimplnxCore/src/SimplnxCore/utils/PythonPluginTemplate.bat @@ -0,0 +1,27 @@ +:: This batch file can be run to activate a specific python virtual environment +:: and set the necessary envionment variables to load the DREAM3D-NX Plugin + +:: If you launch an Anaconda Prompt you can then run this batch file to +:: activate your environment and set the needed variables. If you have installed +:: your anaconda environment into a non-default location then you will need to +:: modify the below line with this command instead, being sure to substitue +:: the proper path to the environment. +:: conda activate --prefix C:/conda3/envs/pyd3d + +:: conda activate @ANACONDA_ENV_NAME@ + +:: ---------------------------------------------------------------------------- +:: The first variable to set is the PYTHONPATH which should point to a +:: directory or directories that contains the top level python plugin +:: folders. If you need to list mulitple directories to search for plugins +:: you can use the ";" character to separate those paths. + +set PYTHONPATH=@PYTHONPATH@ + +:: ---------------------------------------------------------------------------- +:: The next variable is a list of all plugins that you would like to +:: load when DREAM3D-NX (or NXRunner) is run. If you have multiple plugins that +:: you would like to load, list them all separated by a ";" character. + +set SIMPLNX_PYTHON_PLUGINS=@SIMPLNX_PYTHON_PLUGINS@ + diff --git a/src/Plugins/SimplnxCore/src/SimplnxCore/utils/PythonPluginTemplate.sh b/src/Plugins/SimplnxCore/src/SimplnxCore/utils/PythonPluginTemplate.sh new file mode 100644 index 0000000000..dd631a57aa --- /dev/null +++ b/src/Plugins/SimplnxCore/src/SimplnxCore/utils/PythonPluginTemplate.sh @@ -0,0 +1,28 @@ +#!/bin/sh + +# This batch file can be run to activate a specific python virtual environment +# and set the necessary envionment variables to load the DREAM3D-NX Plugin + +# If you launch an Anaconda Prompt you can then run this batch file to +# activate your environment and set the needed variables. If you have installed +# your anaconda environment into a non-default location then you will need to +# modify the below line with this command instead, being sure to substitue +# the proper path to the environment. +# conda activate --prefix /opt/local/conda3/envs/pyd3d + +conda activate @ANACONDA_ENV_NAME@ + +# ---------------------------------------------------------------------------- +# The first variable to set is the PYTHONPATH which should point to a +# directory or directories that contains the top level python plugin +# folders. If you need to list mulitple directories to search for plugins +# you can use the ":" character to separate those paths. + +export PYTHONPATH=@PYTHONPATH@ + +# ---------------------------------------------------------------------------- +# The next variable is a list of all plugins that you would like to +# load when DREAM3D-NX (or NXRunner) is run. If you have multiple plugins that +# you would like to load, list them all separated by a ":" character. + +export SIMPLNX_PYTHON_PLUGINS=@SIMPLNX_PYTHON_PLUGINS@ diff --git a/src/Plugins/SimplnxCore/src/SimplnxCore/utils/PythonPluginTemplateFile.hpp b/src/Plugins/SimplnxCore/src/SimplnxCore/utils/PythonPluginTemplateFile.hpp index b3630bf3a3..9a228ea4b7 100644 --- a/src/Plugins/SimplnxCore/src/SimplnxCore/utils/PythonPluginTemplateFile.hpp +++ b/src/Plugins/SimplnxCore/src/SimplnxCore/utils/PythonPluginTemplateFile.hpp @@ -281,7 +281,7 @@ inline std::string GeneratePythonPlugin(const std::string& pluginName, const std * @return */ inline Result<> WritePythonPluginFiles(const std::filesystem::path& outputDirectory, const std::string& pluginName, const std::string& pluginShortName, const std::string& pluginDescription, - const std::string& pluginFilterList) + const std::string& pluginFilterList, bool createBatchShellScript, const std::string& anacondaEnvName) { auto pluginRootPath = outputDirectory / pluginName; @@ -307,6 +307,31 @@ inline Result<> WritePythonPluginFiles(const std::filesystem::path& outputDirect } } + if(createBatchShellScript) + { +#ifdef __WIN32__ + outputPath = pluginRootPath / "init_evn.bat"; +#else + outputPath = pluginRootPath / "init_evn.sh"; +#endif + AtomicFile initTempFile(outputPath.string(), true); + { + // Scope this so that the file closes first before we then 'commit' with the atomic file + std::ofstream fout(initTempFile.tempFilePath(), std::ios_base::out | std::ios_base::binary); + if(!fout.is_open()) + { + return MakeErrorResult(-74100, fmt::format("Error creating and opening output file at path: {}", initTempFile.tempFilePath().string())); + } + std::string content = PluginBatchFile(); + + content = StringUtilities::replace(content, "@PYTHONPATH@", outputDirectory.string()); + content = StringUtilities::replace(content, "@SIMPLNX_PYTHON_PLUGINS@", pluginName); + content = StringUtilities::replace(content, "@ANACONDA_ENV_NAME@", anacondaEnvName); + + fout << content; + } + } + // Write the __init__.py file outputPath = pluginRootPath / "__init__.py"; { diff --git a/src/Plugins/SimplnxCore/wrapping/python/simplnxpy.cpp b/src/Plugins/SimplnxCore/wrapping/python/simplnxpy.cpp index 3eaebb3aba..712b3801a0 100644 --- a/src/Plugins/SimplnxCore/wrapping/python/simplnxpy.cpp +++ b/src/Plugins/SimplnxCore/wrapping/python/simplnxpy.cpp @@ -286,10 +286,10 @@ PYBIND11_MODULE(simplnx, mod) py::set_shared_data(Internals::k_Key, internals); - // This is required until the pybind11_json library is added which adds the appropriate typecasters - auto json = py::class_(mod, "Json"); - json.def(py::init<>([](std::string_view text) { return nlohmann::json::parse(text); }), "text"_a); - json.def("__str__", [](nlohmann::json& self) { return self.dump(); }); + // This is required until the pybind11_json library is added which adds the appropriate type casters + // auto json = py::class_(mod, "Json"); + // json.def(py::init<>([](std::string_view text) { return nlohmann::json::parse(text); }), "text"_a); + // json.def("__str__", [](nlohmann::json& self) { return self.dump(); }); py::class_ error(mod, "Error"); error.def(py::init<>());