Skip to content

Commit

Permalink
Fix failing unit tests.
Browse files Browse the repository at this point in the history
API: Added name(), human_name(), uuid() to the IFilter python API
BUG: Fixed nullptr crashes.

Signed-off-by: Michael Jackson <[email protected]>
  • Loading branch information
imikejackson committed Dec 20, 2023
1 parent ff26535 commit f05f767
Show file tree
Hide file tree
Showing 20 changed files with 745 additions and 258 deletions.
12 changes: 12 additions & 0 deletions CMakePresets.json
Original file line number Diff line number Diff line change
Expand Up @@ -129,6 +129,10 @@
"Python3_EXECUTABLE": {
"type": "PATH",
"value": "/Users/runner/hostedtoolcache/Python/3.10.13/x64/bin/python3.10"
},
"COMPLEX_PY_DISABLE_HIDDEN_VISIBILITY": {
"type": "BOOL",
"value": "ON"
}
}
},
Expand All @@ -146,6 +150,14 @@
"VCPKG_HOST_TRIPLET": {
"type": "STRING",
"value": "arm64-osx-dynamic"
},
"Python3_EXECUTABLE": {
"type": "PATH",
"value": "/Users/runner/hostedtoolcache/Python/3.10.13/x64/bin/python3.10"
},
"COMPLEX_PY_DISABLE_HIDDEN_VISIBILITY": {
"type": "BOOL",
"value": "ON"
}
}
},
Expand Down
7 changes: 5 additions & 2 deletions src/Plugins/ComplexCore/wrapping/python/complexpy.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -544,8 +544,11 @@ PYBIND11_MODULE(complex, mod)
std::vector<DataPath> outputPaths;
for(const auto* object : self.getTopLevelData())
{
auto topLevelPath = DataPath::FromString(object->getDataPaths()[0].getTargetName()).value();
outputPaths.push_back(topLevelPath);
if(object != nullptr)
{
auto topLevelPath = DataPath::FromString(object->getDataPaths()[0].getTargetName()).value();
outputPaths.push_back(topLevelPath);
}
}
return outputPaths;
}
Expand Down
6 changes: 3 additions & 3 deletions src/complex/Utilities/DataGroupUtilities.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -186,7 +186,6 @@ std::optional<std::vector<DataPath>> GetAllChildDataPaths(const DataStructure& d
{
bool ignore = false;
DataPath childPath = parentGroup.createChildPath(childName);
const DataObject* dataObject = dataStructure.getData(childPath);
for(const auto& ignoredPath : ignoredDataPaths)
{
if(childPath == ignoredPath)
Expand All @@ -195,7 +194,8 @@ std::optional<std::vector<DataPath>> GetAllChildDataPaths(const DataStructure& d
break;
}
}
if(!ignore && (dataObjectType == DataObject::Type::DataObject || dataObject->getDataObjectType() == dataObjectType))
const DataObject* dataObject = dataStructure.getData(childPath);
if(dataObject != nullptr && !ignore && (dataObjectType == DataObject::Type::DataObject || dataObject->getDataObjectType() == dataObjectType))
{
childDataObjects.push_back(childPath);
}
Expand All @@ -211,7 +211,7 @@ std::optional<std::vector<DataPath>> GetAllChildDataPaths(const DataStructure& d
{
std::vector<DataPath> childDataObjects;
const DataObject* dataObject1 = dataStructure.getData(parent);
if(dataObject1->getDataObjectType() == DataObject::Type::DataArray || dataObject1->getDataObjectType() == DataObject::Type::DynamicListArray ||
if(dataObject1 == nullptr || dataObject1->getDataObjectType() == DataObject::Type::DataArray || dataObject1->getDataObjectType() == DataObject::Type::DynamicListArray ||
dataObject1->getDataObjectType() == DataObject::Type::NeighborList || dataObject1->getDataObjectType() == DataObject::Type::ScalarData ||
dataObject1->getDataObjectType() == DataObject::Type::StringArray)
{
Expand Down
23 changes: 12 additions & 11 deletions wrapping/python/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -300,18 +300,19 @@ if(COMPLEX_ENABLE_PYTHON_TESTS)
set(PYTHON_TEST_INPUT_DIR "${complex_SOURCE_DIR}/wrapping/python/examples")

set(COMPLEX_PYTHON_TESTS
"angle_conversion"
"basic_arrays"
"basic_ebsd_ipf"
"import_d3d"
# "angle_conversion"
# "basic_arrays"
# "basic_numpy"
# "create_ensemble_info"
# "generated_file_list"
# "geometry_examples"
# "import_hdf5"
# "output_file"
# "pipeline"
# "read_csv_file"
"basic_numpy"
"create_ensemble_info"
"generated_file_list"
"geometry_examples"
"import_d3d" # Dependent on 'basic_ebsd_ipf' running first
"import_hdf5" # Dependent on 'basic_ebsd_ipf' running first
"output_file"
"pipeline"
"read_csv_file"
# "read_esprit_data"
)

CreatePythonTests(PREFIX "PY_COMPLEX"
Expand Down
13 changes: 12 additions & 1 deletion wrapping/python/CxPybind/CxPybind/CxPybind.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -397,7 +397,18 @@ auto BindFilter(py::handle scope, const Internals& internals)

std::string executeSig = MakePythonSignature<FilterT>("execute", internals);
std::string executeDocString = fmt::format("{}\n\nExecutes the filter\n", executeSig);

filter.def_static("human_name", [&internals]() {
FilterT filter;
return filter.humanName();
});
filter.def_static("name", [&internals]() {
FilterT filter;
return filter.name();
});
filter.def_static("uuid", [&internals]() {
FilterT filter;
return filter.uuid();
});
filter.def_static(
"execute",
[&internals](DataStructure& dataStructure, const py::kwargs& kwargs) {
Expand Down
25 changes: 25 additions & 0 deletions wrapping/python/complex_test_dirs.in.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,21 @@
'''


import complex as cx

def check_filter_result(filter: cx.IFilter, result: cx.IFilter.ExecuteResult):
if len(result.warnings) != 0:
print(f'{filter.name()} :: Warnings: {result.warnings}')

has_errors = len(result.errors) != 0
if has_errors:
print(f'{filter.name()} :: Errors: {result.errors}')
raise RuntimeError(result)

print(f"{filter.name()} :: No errors running the filter")


def GetBuildDirectory():
return '${CMAKE_LIBRARY_OUTPUT_DIRECTORY}'

Expand All @@ -23,3 +38,13 @@ def GetComplexPythonSourceDir():

def GetComplexSourceDir():
return '${complex_SOURCE_DIR}'

def print_all_paths():
print(f'#### Important Filesystem Paths ####')
print(f' GetBuildDirectory: {GetBuildDirectory()}')
print(f' GetTestDirectory: {GetTestDirectory()}')
print(f' GetTestTempDirectory: {GetTestTempDirectory()}')
print(f' GetDataDirectory: {GetDataDirectory()}')
print(f' GetComplexPythonSourceDir: {GetComplexPythonSourceDir()}')
print(f' GetComplexSourceDir: {GetComplexSourceDir()}')
print('#######################################')
44 changes: 43 additions & 1 deletion wrapping/python/docs/source/Overview.rst
Original file line number Diff line number Diff line change
Expand Up @@ -181,7 +181,49 @@ form a **Pipeline**, in which the data structure flows through the set of **Filt
being modified along the way. If a **Filter** reads in data from outside of DREAM3D-NX,
then the new data will be incorporated into the existing data structure. Or, if no
data structure yet exists (e.g, starting from a “blank slate”), a new one will be
created.
created.

.. py:class:: complex.IFilter
This class holds an instantiation of a DREAM3D-NX filter. The filter can be
preflighted, executed or just held for later execution.

.. py:method:: name()
:return: The C++ classname of the filter
:rtype: str

.. py:method:: human_name()
:return: What the user would see in the DREAM3D-NX application
:rtype: str

.. py:method:: uuid()
:return: The unique identifier of the filter
:rtype: str

.. py:method:: execute()
:return: A complex.IFilter.Result object that contains any warnings or errors
that were encountered during the execution of the filter.
:rtype: complex.IFilter.Result

.. py:method:: preflight()
:return: A complex.IFilter.Result object that contains any warnings or errors
that were encountered during the preflight of the filter.
:rtype: complex.IFilter.Result

.. code:: python
create_array_filter = cx.CreateDataArray()
print(f'{create_array_filter.name()}')
print(f'{create_array_filter.human_name()}')
print(f'{create_array_filter.uuid()}')
For examles of executing a filter, please see any of the example python files included
with the source package.

.. _Pipeline:
.. _Plugin:
Expand Down
56 changes: 45 additions & 11 deletions wrapping/python/examples/angle_conversion.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,40 @@
# Import the DREAM3D Base library and Plugins
"""
Important Note
==============
This python file can be used as an example of how to execute a number of DREAM3D-NX
filters one after another, if you plan to use the codes below (and you are welcome to),
there are a few things that you, the developer, should take note of:
Import Statements
-----------------
You will most likely *NOT* need to include the following code:
.. code:: python
import complex_test_dirs as cxtest
Filter Error Detection
----------------------
In each section of code a filter is created and executed immediately. This may or
may *not* be what you want to do. You can also preflight the filter to verify the
correctness of the filters before executing the filter **although** this is done
for you when the filter is executed. As such, you will want to check the 'result'
variable to see if there are any errors or warnings. If there **are** any then
you, as the developer, should act appropriately on the errors or warnings.
More specifically, this bit of code:
.. code:: python
cxtest.check_filter_result(cxor.ReadAngDataFilter, result)
is used by the simplnx unit testing framework and should be replaced by your own
error checking code. You are welcome to look up the function definition and use
that.
"""
import complex as cx

import itkimageprocessing as cxitk
Expand All @@ -7,6 +43,10 @@

import numpy as np

#------------------------------------------------------------------------------
# Print the various filesystem paths that are pregenerated for this machine.
#------------------------------------------------------------------------------
cxtest.print_all_paths()


# ------------------------------------------------------------------------------
Expand All @@ -22,11 +62,8 @@
tuple_dimensions=[[99]],
output_data_array=array_path,
initialization_value='0')
if len(result.errors) != 0:
print('Errors: {}', result.errors)
print('Warnings: {}', result.warnings)
else:
print("No errors running the CreateDataArray")
cxtest.check_filter_result(cx.CreateDataArray, result)


# Get a numpy.view into the newly created DataArray
data_array = data_structure[array_path]
Expand All @@ -48,11 +85,8 @@
input_type=0,
output_orientation_array_name='Quaternions',
output_type=2)
if len(result.errors) != 0:
print('Errors: {}', result.errors)
print('Warnings: {}', result.warnings)
else:
print("No errors running the ConvertOrientations")
cxtest.check_filter_result(cxor.ConvertOrientations, result)


# Get the Quaternions and print them out.
data_array = data_structure[quat_path]
Expand Down
Loading

0 comments on commit f05f767

Please sign in to comment.