diff --git a/.github/workflows/linux.yml b/.github/workflows/linux.yml index 52528f07db..503f8f3b0d 100644 --- a/.github/workflows/linux.yml +++ b/.github/workflows/linux.yml @@ -43,7 +43,7 @@ jobs: sudo apt-get -y install ninja-build - name: Install Sphinx run: | - sudo pip install sphinx myst-parser sphinx-markdown-tables sphinx_rtd_theme + sudo pip install sphinx myst-parser sphinx-markdown-tables sphinx_rtd_theme numpy - name: Setup NuGet Credentials shell: bash run: | diff --git a/.github/workflows/macos.yml b/.github/workflows/macos.yml index 7a388ab2f0..26f98161c9 100644 --- a/.github/workflows/macos.yml +++ b/.github/workflows/macos.yml @@ -32,7 +32,7 @@ jobs: brew install ninja - name: Install Sphinx run: | - sudo pip3 install sphinx myst-parser sphinx-markdown-tables sphinx_rtd_theme + sudo pip3 install sphinx myst-parser sphinx-markdown-tables sphinx_rtd_theme numpy - name: Setup NuGet Credentials shell: bash run: | diff --git a/.github/workflows/windows.yml b/.github/workflows/windows.yml index fd649a3d4f..ca2981560a 100644 --- a/.github/workflows/windows.yml +++ b/.github/workflows/windows.yml @@ -49,7 +49,7 @@ jobs: -source "https://nuget.pkg.github.com/BlueQuartzSoftware/index.json" - name: Install Sphinx run: | - pip install sphinx myst-parser sphinx-markdown-tables sphinx_rtd_theme + pip install sphinx myst-parser sphinx-markdown-tables sphinx_rtd_theme numpy - name: Configure run: | cmake --preset ci-windows-${{matrix.toolset}} ${{github.workspace}} -T ${{matrix.toolset}} diff --git a/CMakeLists.txt b/CMakeLists.txt index da38d7f90d..de03b2f339 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -63,7 +63,7 @@ option(COMPLEX_ENABLE_INSTALL "Enables COMPLEX install rules" ON) file(TO_CMAKE_PATH "${CMAKE_COMMAND}" CMAKE_COMMAND_NORM) project(complex - VERSION 1.2.0 + VERSION 1.2.1 DESCRIPTION "SIMPL Redesign" HOMEPAGE_URL "https://github.com/BlueQuartzSoftware/complex" LANGUAGES CXX diff --git a/CMakePresets.json b/CMakePresets.json index fcb3e81af7..427ccbfa40 100644 --- a/CMakePresets.json +++ b/CMakePresets.json @@ -33,6 +33,10 @@ "type": "BOOL", "value": "ON" }, + "COMPLEX_ENABLE_PYTHON_TESTS": { + "type": "BOOL", + "value": "ON" + }, "COMPLEX_EMBED_PYTHON": { "type": "BOOL", "value": "OFF" diff --git a/cmake/Utility.cmake b/cmake/Utility.cmake index e3eeb42f2c..ed62608cde 100644 --- a/cmake/Utility.cmake +++ b/cmake/Utility.cmake @@ -460,3 +460,86 @@ function(cmpBuildDateRevisionString) endif() endfunction() + + +#------------------------------------------------------------------------------- +# @Brief function AddPythonTest +# @ NAME +# @ FILE +# @ PYTHONPATH +#------------------------------------------------------------------------------- +function(AddPythonTest) + set(options ) + set(oneValueArgs NAME FILE) + set(multiValueArgs PYTHONPATH) + cmake_parse_arguments(ARGS "${options}" "${oneValueArgs}" "${multiValueArgs}" ${ARGN}) + + if(COMPLEX_BUILD_PYTHON) + if(WIN32) + add_test(NAME ${ARGS_NAME} + COMMAND ${complex_SOURCE_DIR}/wrapping/python/testing/anaconda_test.bat + ) + + set_property(TEST ${ARGS_NAME} + PROPERTY + ENVIRONMENT + "PYTHON_TEST_FILE=${ARGS_FILE}" + ) + else() + add_test(NAME ${ARGS_NAME} + COMMAND ${complex_SOURCE_DIR}/wrapping/python/testing/anaconda_test.sh + ) + + set_property(TEST ${ARGS_NAME} + PROPERTY + ENVIRONMENT + "PYTHON_TEST_FILE=${ARGS_FILE}" + ) + endif() + else() + add_test(NAME ${ARGS_NAME} + COMMAND ${PYTHON_EXECUTABLE} ${ARGS_FILE} + ) + endif() + + if(WIN32) + string(REPLACE ";" "\\;" ARGS_PYTHONPATH "${ARGS_PYTHONPATH}") + else() + string(REPLACE ";" ":" ARGS_PYTHONPATH "${ARGS_PYTHONPATH}") + endif() + + set_property(TEST ${ARGS_NAME} + APPEND + PROPERTY + ENVIRONMENT + "PYTHONPATH=${ARGS_PYTHONPATH}" + "${complex_PYTHON_TEST_ENV}" + ) +endfunction() + +#------------------------------------------------------------------------------- +# @Brief function CreatePythonTests +# @ PREFIX +# @ INPUT_DIR +# @ TEST_NAMES +#------------------------------------------------------------------------------- +function(CreatePythonTests) + set(options) + set(oneValueArgs PREFIX INPUT_DIR) + set(multiValueArgs TEST_NAMES) + cmake_parse_arguments(ARGS "${options}" "${oneValueArgs}" "${multiValueArgs}" ${ARGN}) + + set(TESTS_PYTHONPATH + "$" + ) + + foreach(test ${ARGS_TEST_NAMES}) + string(REPLACE "/" "_" test_name ${test}) + set(PY_TEST_NAME ${ARGS_PREFIX}_${test_name}) + + AddPythonTest(NAME ${PY_TEST_NAME} + FILE ${ARGS_INPUT_DIR}/${test}.py + PYTHONPATH ${TESTS_PYTHONPATH} + ) + endforeach() +endfunction() diff --git a/conda/meta.yaml b/conda/meta.yaml index 1d8c4d1914..171d25f9c4 100644 --- a/conda/meta.yaml +++ b/conda/meta.yaml @@ -1,5 +1,5 @@ {% set name = "complex" %} -{% set version = "1.2.0" %} +{% set version = "1.2.1" %} package: name: {{ name|lower }} diff --git a/conda/recipe.yaml b/conda/recipe.yaml index 318d1f1b3b..161527c01e 100644 --- a/conda/recipe.yaml +++ b/conda/recipe.yaml @@ -1,5 +1,5 @@ context: - version: "1.2.0" + version: "1.2.1" name: complex package: diff --git a/src/Plugins/ComplexCore/src/ComplexCore/Filters/CreateDataArray.cpp b/src/Plugins/ComplexCore/src/ComplexCore/Filters/CreateDataArray.cpp index 689f97823c..1370c1f56c 100644 --- a/src/Plugins/ComplexCore/src/ComplexCore/Filters/CreateDataArray.cpp +++ b/src/Plugins/ComplexCore/src/ComplexCore/Filters/CreateDataArray.cpp @@ -134,7 +134,8 @@ IFilter::PreflightResult CreateDataArray::preflightImpl(const DataStructure& dat if(!useDims) { return MakePreflightErrorResult( - -78602, "The DataArray to be created is not within an AttributeMatrix, so the dimensions cannot be determined implicitly. Check Set Tuple Dimensions to set the dimensions"); + -78602, fmt::format("The DataArray to be created '{}'is not within an AttributeMatrix, so the dimensions cannot be determined implicitly. Check Set Tuple Dimensions to set the dimensions", + dataArrayPath.toString())); } else { diff --git a/src/Plugins/ComplexCore/src/ComplexCore/Filters/ReadTextDataArrayFilter.cpp b/src/Plugins/ComplexCore/src/ComplexCore/Filters/ReadTextDataArrayFilter.cpp index b0a2daae29..678a60bcc3 100644 --- a/src/Plugins/ComplexCore/src/ComplexCore/Filters/ReadTextDataArrayFilter.cpp +++ b/src/Plugins/ComplexCore/src/ComplexCore/Filters/ReadTextDataArrayFilter.cpp @@ -106,7 +106,8 @@ IFilter::PreflightResult ReadTextDataArrayFilter::preflightImpl(const DataStruct if(!useDims) { return MakePreflightErrorResult( - -77602, "The DataArray to be created is not within an AttributeMatrix, so the dimensions cannot be determined implicitly. Check Set Tuple Dimensions to set the dimensions"); + -78602, fmt::format("The DataArray to be created '{}'is not within an AttributeMatrix, so the dimensions cannot be determined implicitly. Check Set Tuple Dimensions to set the dimensions", + arrayPath.toString())); } else { diff --git a/src/Plugins/ComplexCore/wrapping/python/complexpy.cpp b/src/Plugins/ComplexCore/wrapping/python/complexpy.cpp index 68bad4d80c..bea5159e64 100644 --- a/src/Plugins/ComplexCore/wrapping/python/complexpy.cpp +++ b/src/Plugins/ComplexCore/wrapping/python/complexpy.cpp @@ -10,7 +10,6 @@ #include "ComplexCore/ComplexCoreFilterBinding.hpp" #include - #include #include #include @@ -80,6 +79,7 @@ #include #include #include +#include #include @@ -510,6 +510,37 @@ PYBIND11_MODULE(complex, mod) dataStructure.def_property_readonly("size", &DataStructure::getSize); dataStructure.def("__len__", &DataStructure::getSize); dataStructure.def("remove", py::overload_cast(&DataStructure::removeData)); + dataStructure.def("hierarchy_to_str", [](DataStructure& self) { + std::stringstream ss; + self.exportHierarchyAsText(ss); + return ss.str(); + }); + dataStructure.def("hierarchy_to_graphviz", [](DataStructure& self) { + std::stringstream ss; + self.exportHierarchyAsGraphViz(ss); + return ss.str(); + }); + dataStructure.def("get_children", [](DataStructure& self, complex::DataPath& parentPath) { + if(parentPath.empty()) + { + std::vector outputPaths; + for(const auto* object : self.getTopLevelData()) + { + auto topLevelPath = DataPath::FromString(object->getDataPaths()[0].getTargetName()).value(); + outputPaths.push_back(topLevelPath); + } + return outputPaths; + } + else + { + auto result = complex::GetAllChildDataPaths(self, parentPath); + if(result) + { + return result.value(); + } + return std::vector{}; + } + }); py::class_> baseGroup(mod, "BaseGroup"); baseGroup.def("contains", py::overload_cast(&BaseGroup::contains, py::const_)); diff --git a/src/complex/DataStructure/DataStructure.cpp b/src/complex/DataStructure/DataStructure.cpp index 6665602ab0..2db3a9650b 100644 --- a/src/complex/DataStructure/DataStructure.cpp +++ b/src/complex/DataStructure/DataStructure.cpp @@ -870,72 +870,77 @@ void DataStructure::resetIds(DataObject::IdType startingId) m_RootGroup.updateIds(updatedIds); } -void DataStructure::exportHeirarchyAsGraphViz(std::ostream& outputStream) const +void DataStructure::exportHierarchyAsGraphViz(std::ostream& outputStream) const { // initialize dot file outputStream << "digraph DataGraph {\n" << "\tlabelloc =\"t\"\n" - << "\trankdir=LR;\n\n"; - + << "\trankdir=LR;\n" + << "\tlabel=\"DataStructure Hierarchy\"\n" + << "\tlabelloc=\"t\"\n" + << "\tfontcolor=\"#FFFFFA\"\n" + << "\tfontsize=12\n" + << "\tgraph [splines=true bgcolor=\"#242627\"]\n" + << "\tnode [shape=record style=\"filled\" fillcolor=\"#1D7ECD\" fontsize=12 fontcolor=\"#FFFFFA\"]\n" + << "\tedge [dir=front arrowtail=empty style=\"\" color=\"#FFFFFA\"]\n\n"; // set base case for(const auto* object : getTopLevelData()) { auto topLevelPath = DataPath::FromString(object->getDataPaths()[0].getTargetName()).value(); auto optionalDataPaths = GetAllChildDataPaths(*this, topLevelPath); + outputStream << "\n/* Top level DataObject: " << topLevelPath.getTargetName() << " */\n\"" << topLevelPath.getTargetName() << "\";\n"; - if(!optionalDataPaths.has_value() || optionalDataPaths.value().size() == 0) + if(optionalDataPaths.has_value() && !optionalDataPaths.value().empty()) { - outputStream << "\"" << topLevelPath.getTargetName() << "\";\n\n"; + // Begin recursion + recurseHierarchyToGraphViz(outputStream, optionalDataPaths.value(), topLevelPath.getTargetName()); } - - // Begin recursion - recurseHeirarchyToGraphViz(outputStream, optionalDataPaths.value(), topLevelPath.getTargetName()); } // close dot file outputStream << "}" << std::endl; // for readability } -void DataStructure::recurseHeirarchyToGraphViz(std::ostream& outputStream, const std::vector paths, const std::string& parent) const +void DataStructure::exportHierarchyAsText(std::ostream& outputStream) const { - for(const auto& path : paths) + // set base case + for(const auto* object : getTopLevelData()) { - // Output parent node, child node, and edge connecting them in .dot format - outputStream << "\"" << parent << "\" -> \"" << path.getTargetName() << "\"\n"; + auto topLevelPath = DataPath::FromString(object->getDataPaths()[0].getTargetName()).value(); + outputStream << k_Delimiter << topLevelPath.getTargetName() << "\n"; + auto optionalDataPaths = GetAllChildDataPaths(*this, topLevelPath); - // pull child paths or skip to next iteration - auto optionalChildPaths = GetAllChildDataPaths(*this, path); - if(!optionalChildPaths.has_value() || optionalChildPaths.value().size() == 0) + if(optionalDataPaths.has_value() && !optionalDataPaths.value().empty()) { - continue; + // Begin recursion + recurseHierarchyToText(outputStream, optionalDataPaths.value(), ""); } - - // recurse - recurseHeirarchyToGraphViz(outputStream, optionalChildPaths.value(), path.getTargetName()); } - outputStream << "\n"; // for readability + outputStream << std::endl; // for readability } -void DataStructure::exportHeirarchyAsText(std::ostream& outputStream) const +void DataStructure::recurseHierarchyToGraphViz(std::ostream& outputStream, const std::vector paths, const std::string& parent) const { - // set base case - for(const auto* object : getTopLevelData()) + for(const auto& path : paths) { - auto topLevelPath = DataPath::FromString(object->getDataPaths()[0].getTargetName()).value(); - auto optionalDataPaths = GetAllChildDataPaths(*this, topLevelPath); - - outputStream << k_Delimiter << topLevelPath.getTargetName() << "\n"; + auto* dataObjectPtr = getData(path); + // Output parent node, child node, and edge connecting them in .dot format + outputStream << "\"" << parent << "\" -> \"" << path.getTargetName() << "\"\n"; - if(optionalDataPaths.has_value() || optionalDataPaths.value().size() != 0) + // pull child paths or skip to next iteration + auto optionalChildPaths = GetAllChildDataPaths(*this, path); + if(!optionalChildPaths.has_value() || optionalChildPaths.value().empty()) { - // Begin recursion - recurseHeirarchyToText(outputStream, optionalDataPaths.value(), ""); + continue; } + + // recurse + recurseHierarchyToGraphViz(outputStream, optionalChildPaths.value(), path.getTargetName()); } - outputStream << std::endl; // for readability + // outputStream << "\n"; // for readability } -void DataStructure::recurseHeirarchyToText(std::ostream& outputStream, const std::vector paths, std::string indent) const +void DataStructure::recurseHierarchyToText(std::ostream& outputStream, const std::vector paths, std::string indent) const { indent += " "; @@ -946,13 +951,13 @@ void DataStructure::recurseHeirarchyToText(std::ostream& outputStream, const std // pull child paths or skip to next iteration auto optionalChildPaths = GetAllChildDataPaths(*this, path); - if(!optionalChildPaths.has_value() || optionalChildPaths.value().size() == 0) + if(!optionalChildPaths.has_value() || optionalChildPaths.value().empty()) { continue; } // recurse - recurseHeirarchyToText(outputStream, optionalChildPaths.value(), indent); + recurseHierarchyToText(outputStream, optionalChildPaths.value(), indent); } } diff --git a/src/complex/DataStructure/DataStructure.hpp b/src/complex/DataStructure/DataStructure.hpp index c1e0016a6c..3a9af13e1b 100644 --- a/src/complex/DataStructure/DataStructure.hpp +++ b/src/complex/DataStructure/DataStructure.hpp @@ -665,14 +665,14 @@ class COMPLEX_EXPORT DataStructure * @param outputStream the child class of ostream to output dot syntax to * @return */ - void exportHeirarchyAsGraphViz(std::ostream& outputStream) const; + void exportHierarchyAsGraphViz(std::ostream& outputStream) const; /** * @brief Outputs data graph in console readable format * @param outputStream the child class of ostream to output to * @return */ - void exportHeirarchyAsText(std::ostream& outputStream) const; + void exportHierarchyAsText(std::ostream& outputStream) const; /** * @brief Copy assignment operator. The copied DataStructure's observers are not retained. @@ -800,7 +800,7 @@ class COMPLEX_EXPORT DataStructure * @param parent name of the calling parent to output * @return */ - void recurseHeirarchyToGraphViz(std::ostream& outputStream, const std::vector paths, const std::string& parent) const; + void recurseHierarchyToGraphViz(std::ostream& outputStream, const std::vector paths, const std::string& parent) const; /** * @brief The recursive function to parse graph and dump names to and output stream in @@ -810,7 +810,7 @@ class COMPLEX_EXPORT DataStructure * @param indent the indent for the heirarchy * @return */ - void recurseHeirarchyToText(std::ostream& outputStream, const std::vector paths, std::string indent) const; + void recurseHierarchyToText(std::ostream& outputStream, const std::vector paths, std::string indent) const; /** * @brief Notifies observers to the provided message. diff --git a/test/DataStructTest.cpp b/test/DataStructTest.cpp index 4677bfb0c4..a25e87b203 100644 --- a/test/DataStructTest.cpp +++ b/test/DataStructTest.cpp @@ -17,6 +17,7 @@ #include "complex/UnitTest/UnitTestCommon.hpp" #include "complex/Utilities/DataArrayUtilities.hpp" #include "complex/Utilities/DataGroupUtilities.hpp" +#include "complex/unit_test/complex_test_dirs.hpp" #include @@ -42,6 +43,26 @@ constexpr StringLiteral k_SharedPolyhedrons = "SharedPolyhedronList"; constexpr StringLiteral k_HexGeo = "Hex Geometry"; } // namespace +// This test will ensure we don't run into runtime exceptions trying to run the functions +TEST_CASE("ComplexCore::exportHierarchyAsGraphViz") +{ + DataStructure dataStructure = UnitTest::CreateComplexMultiLevelDataGraph(); + auto outputPath = fs::path(fmt::format("{}/exportHierarchyAsGraphViz_test.dot", unit_test::k_BinaryTestOutputDir)); + std::cout << outputPath << std::endl; + std::ofstream output(outputPath, std::ios_base::trunc); + dataStructure.exportHierarchyAsGraphViz(output); +} + +// This test will ensure we don't run into runtime exceptions trying to run the functions +TEST_CASE("ComplexCore::exportHierarchyAsText") +{ + DataStructure dataStructure = UnitTest::CreateComplexMultiLevelDataGraph(); + auto outputPath = fs::path(fmt::format("{}/exportHierarchyAsText_test.txt", unit_test::k_BinaryTestOutputDir)); + std::cout << outputPath << std::endl; + std::ofstream output(outputPath, std::ios_base::trunc); + dataStructure.exportHierarchyAsText(output); +} + DataStructure createTestDataStructure() { DataStructure dataStruct; diff --git a/wrapping/python/CMakeLists.txt b/wrapping/python/CMakeLists.txt index af0d2bfc1a..240dbf196e 100644 --- a/wrapping/python/CMakeLists.txt +++ b/wrapping/python/CMakeLists.txt @@ -278,3 +278,45 @@ option(COMPLEX_ENABLE_SPHINX_DOCS "Enables the Sphinx based documentation genera if(COMPLEX_ENABLE_SPHINX_DOCS) add_subdirectory(${CMAKE_CURRENT_SOURCE_DIR}/docs ${complex_BINARY_DIR}/sphinx_docs) endif() + +#------------------------------------------------------------------------------ +# Create the Python Unit tests +#------------------------------------------------------------------------------ +option(COMPLEX_ENABLE_PYTHON_TESTS "Enables python based unit tests" OFF) +if(COMPLEX_ENABLE_PYTHON_TESTS) + + file(READ ${complex_SOURCE_DIR}/wrapping/python/complex_test_dirs.in.py COMPLEX_TEST_DIRS_FILE) + + string(REPLACE "\${CMAKE_LIBRARY_OUTPUT_DIRECTORY}" $ COMPLEX_TEST_DIRS_FILE ${COMPLEX_TEST_DIRS_FILE}) + string(REPLACE "\${complex_BINARY_DIR}" ${complex_BINARY_DIR} COMPLEX_TEST_DIRS_FILE ${COMPLEX_TEST_DIRS_FILE}) + string(REPLACE "\${DREAM3D_DATA_DIR}" ${DREAM3D_DATA_DIR} COMPLEX_TEST_DIRS_FILE ${COMPLEX_TEST_DIRS_FILE}) + string(REPLACE "\${complex_SOURCE_DIR}" ${complex_SOURCE_DIR} COMPLEX_TEST_DIRS_FILE ${COMPLEX_TEST_DIRS_FILE}) + + file(GENERATE + OUTPUT "$/complex_test_dirs.py" + CONTENT ${COMPLEX_TEST_DIRS_FILE} + ) + + set(PYTHON_TEST_INPUT_DIR "${complex_SOURCE_DIR}/wrapping/python/examples") + + set(COMPLEX_PYTHON_TESTS + "angle_conversion" + "basic_arrays" + "basic_ebsd_ipf" + "basic_numpy" + "create_ensemble_info" + "generated_file_list" + "geometry_examples" + "import_d3d" + "import_hdf5" + "output_file" + "pipeline" + "read_csv_file" + ) + + CreatePythonTests(PREFIX "PY_COMPLEX" + INPUT_DIR ${PYTHON_TEST_INPUT_DIR} + TEST_NAMES ${COMPLEX_PYTHON_TESTS} + ) + +endif() diff --git a/wrapping/python/ReadMe.md b/wrapping/python/ReadMe.md index b010aba7dd..e608d6cf56 100644 --- a/wrapping/python/ReadMe.md +++ b/wrapping/python/ReadMe.md @@ -1,5 +1,20 @@ # Complex Python Information +## Checklist when updating Python Bindings + +- Update Version number. + + - If you add API then update the third number + - If you break API (any where in complex), update the second number + +- Document **ALL** new API in the appropriate documentation file(s) +- Create a ReleaseNotes_1XX.rst file with the appropriate highlights from the release +- Create example python code for any new API +- Update example python codes for any changed API +- Add unit test for any NEW API +- Update Unit test for changed API +- Tag the repository with the correct version in the correct semantic form + ## Creating the Python Bindings ### MacOS: Use Mamba diff --git a/wrapping/python/ToDo.md b/wrapping/python/ToDo.md new file mode 100644 index 0000000000..43e8a1368f --- /dev/null +++ b/wrapping/python/ToDo.md @@ -0,0 +1,10 @@ +# ToDo list for python bindings + +- Create each kind of geometry using the python bindings + + - combine that with numpy to generate some nodes for a node geometry + +- Document all wrapped methods in the complexpy.cpp file. +- Example of using MatPlotLib to generate a plot and save the whole plot as an image file +- Example of using Pandas DataFrame +- Example of looping over X number of EBSD files and generate a Pole figure for each file diff --git a/wrapping/python/complex_test_dirs.in.py b/wrapping/python/complex_test_dirs.in.py new file mode 100644 index 0000000000..3b489cd664 --- /dev/null +++ b/wrapping/python/complex_test_dirs.in.py @@ -0,0 +1,25 @@ +''' module to get build specific directories + This file is generated during the cmake configure phase. This file does *NOT* + however use the standard `cmake_configure_file()` command but instead uses + a custom generation cmake code. If you add new `${}` style variables, you will + need to update those custom CMake codes. + + ''' + +def GetBuildDirectory(): + return '${CMAKE_LIBRARY_OUTPUT_DIRECTORY}' + +def GetTestDirectory(): + return '${complex_BINARY_DIR}/Testing' + +def GetTestTempDirectory(): + return '${complex_BINARY_DIR}/Testing/Temporary' + +def GetDataDirectory(): + return '${DREAM3D_DATA_DIR}' + +def GetComplexPythonSourceDir(): + return '${complex_SOURCE_DIR}/wrapping/python' + +def GetComplexSourceDir(): + return '${complex_SOURCE_DIR}' diff --git a/wrapping/python/docs/index_template.rst b/wrapping/python/docs/index_template.rst index 4575a5118e..173cae6475 100644 --- a/wrapping/python/docs/index_template.rst +++ b/wrapping/python/docs/index_template.rst @@ -5,7 +5,7 @@ DREAM3D-NX Python Docs ======================= -Latest Version: 1.2.0 +Latest Version: 1.2.1 --------------------- The *complex* library can be installed through an Anaconda packages from the *BlueQuartzSoftware* channel. This can be achieved @@ -32,6 +32,7 @@ by creating a new virtual environment Reference_Frame_Notes ReleaseNotes_110 ReleaseNotes_120 + ReleaseNotes_121 @PLUGIN_LIST@ Indices and tables diff --git a/wrapping/python/docs/source/DataObjects.rst b/wrapping/python/docs/source/DataObjects.rst index 68a7b34db0..9b312dbcd1 100644 --- a/wrapping/python/docs/source/DataObjects.rst +++ b/wrapping/python/docs/source/DataObjects.rst @@ -1,10 +1,11 @@ DataStructure Objects ====================== -.. _DataStructure: +.. py:module:: complex + DataStructure --------------- +---------------- The **complex** DataStructure can be filled with various types of objects. Those are all listed below. In the **DREAM3D-NX** user interface, the DataStructure of any @@ -16,10 +17,51 @@ a yellow box at the right side of the user interface. :height: 809 :scale: 45 + +- All DataObjects are stored in a DataStructure. +- Multiple DataStructure objects are allowed in a python program. + +.. _DataStructure: +.. py:class:: DataStructure + + .. py:method:: size() + + :return: An integer that is the total number of all objects that are held by the DataStructure. + :rtype: int + + .. py:method:: remove(data_path) + + :param DataPath_ data_path: The DataPath to get the children. An empty DataPath object will return the top level DataPaths. + :return: A boolean indicating if the path was removed or not. + :rtype: Bool + + .. py:method:: hierarchy_to_str() + + :return: A string that attempts to show the internal hierarchy of the DataStructure + :rtype: string + + .. py:method:: hierarchy_to_graphviz() + + :return: A string that attempts to show the internal hierarchy of the DataStructure formatted in the GraphViz 'dot' language. + :rtype: string + + .. py:method:: get_children(data_path) + + :param DataPath_ data_path: The DataPath to get the children. An empty DataPath object will return the top level DataPaths. + :return: A string that attempts to show the internal hierarchy of the DataStructure + :rtype: List of DataPath_ + .. code:: python + # this is just sample code. The developer is expected to use these on well + # constructed DataStructure objects. data_structure = cx.DataStructure() - + num_objects = data_structure.size + did_remove = data_structure.remove(complex.DataPath("/Path/to/Object")) + hierarchy = data_structure.hierarchy_to_str() + hierarchy_gv = data_structure.hierarchy_to_graphviz() + top_level_child_paths = data_structure.get_children() + child_paths = data_structure.get_children(complex.DataPath("Group")) .. _DataObject: @@ -79,9 +121,9 @@ codes that are based on the `complex