Skip to content

Commit

Permalink
ENH: GeneratePythonPlugin can generate batch/shell init file. (#896)
Browse files Browse the repository at this point in the history
Signed-off-by: Michael Jackson <[email protected]>
  • Loading branch information
imikejackson authored Mar 28, 2024
1 parent d43cc50 commit 8f1a45d
Show file tree
Hide file tree
Showing 11 changed files with 144 additions and 25 deletions.
16 changes: 13 additions & 3 deletions src/Plugins/SimplnxCore/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -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})
Expand All @@ -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}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,8 @@ struct SIMPLNXCORE_EXPORT GeneratePythonSkeletonInputValues
std::string pluginName;
std::string pluginHumanName;
std::string filterNames;
bool createBatchShellScript;
std::string anacondaEnvName;
};

/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -66,11 +66,15 @@ Parameters GeneratePythonSkeletonFilter::parameters() const
params.insert(
std::make_unique<StringParameter>(k_PluginFilterNames, "Filter Names (comma-separated)", "The names of filters that will be created, separated by commas (,).", "FirstFilter,SecondFilter"));

params.insertLinkableParameter(
std::make_unique<BoolParameter>(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<StringParameter>(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;
}

Expand Down Expand Up @@ -135,6 +139,8 @@ Result<> GeneratePythonSkeletonFilter::executeImpl(DataStructure& dataStructure,
inputValues.pluginName = filterArgs.value<StringParameter::ValueType>(k_PluginName_Key);
inputValues.pluginHumanName = filterArgs.value<StringParameter::ValueType>(k_PluginHumanName_Key);
inputValues.filterNames = filterArgs.value<StringParameter::ValueType>(k_PluginFilterNames);
inputValues.createBatchShellScript = filterArgs.value<BoolParameter::ValueType>(k_CreateBatchFile_Key);
inputValues.anacondaEnvName = filterArgs.value<StringParameter::ValueType>(k_AnacondaEnvName_Key);

return GeneratePythonSkeleton(dataStructure, messageHandler, shouldCancel, &inputValues)();
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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";

/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,20 +8,16 @@ 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
:rtype: string
"""
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
Expand All @@ -36,20 +32,34 @@ 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
:rtype: #PYTHON_FILTER_NAME#
"""
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.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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
Original file line number Diff line number Diff line change
@@ -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@

Original file line number Diff line number Diff line change
@@ -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@
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -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";
{
Expand Down
8 changes: 4 additions & 4 deletions src/Plugins/SimplnxCore/wrapping/python/simplnxpy.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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_<nlohmann::json>(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_<nlohmann::json>(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> error(mod, "Error");
error.def(py::init<>());
Expand Down

0 comments on commit 8f1a45d

Please sign in to comment.