Skip to content

Commit

Permalink
Added attributeExists method on IO and ReadDataWrapper::exists method…
Browse files Browse the repository at this point in the history
…s to check that an object actually exists
  • Loading branch information
oruebel committed Sep 22, 2024
1 parent 3c4b2d7 commit aad6928
Show file tree
Hide file tree
Showing 7 changed files with 61 additions and 1 deletion.
10 changes: 9 additions & 1 deletion docs/pages/userdocs/read.dox
Original file line number Diff line number Diff line change
Expand Up @@ -237,7 +237,7 @@
*
* \subsection read_design_example_read_during Reading Datasets and Attributes
*
* \subsubsection read_design_example_laxy_read Lazy data access
* \subsubsection read_design_example_lazy_read Lazy data access
*
* All data read is implemented lazily, i.e., AqNWB does not load data into memory
* until we make a request to do so. To access data lazily, datasets and attributes are
Expand All @@ -249,6 +249,14 @@
*
* \snippet tests/examples/test_ecephys_data_read.cpp example_read_get_data_wrapper_snippet
*
* \subsubsection read_design_example_check_exists Check that the object exists
*
* In particular for fields that are optional, it is useful to first check that the field
* actually exists using the \ref AQNWB::IO::ReadDataWrapper::exists "exists" method of
* our \ref AQNWB::IO::ReadDataWrapper "ReadDataWrapper".
*
* \snippet tests/examples/test_ecephys_data_read.cpp example_read_check_data_exists_snippet
*
* \subsubsection read_design_example_load_data Read data into memory
*
* To load the data values, we can then use the \ref AQNWB::IO::ReadDataWrapper::valuesGeneric "valuesGeneric"
Expand Down
10 changes: 10 additions & 0 deletions src/io/BaseIO.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -351,6 +351,16 @@ class BaseIO
*/
virtual bool objectExists(const std::string& path) = 0;

/**
* @brief Checks whether an Attribute exists at the
* location in the file.
* @param path The location of the attribute in the file. I.e.,
* this is a combination of that parent object's
* path and the name of the attribute.
* @return Whether the attribute exists.
*/
virtual bool attributeExists(const std::string& path) = 0;

/**
* @brief Convenience function for creating NWB related attributes.
* @param path The location of the object in the file.
Expand Down
19 changes: 19 additions & 0 deletions src/io/ReadIO.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -284,6 +284,25 @@ class ReadDataWrapper
*/
inline std::shared_ptr<IO::BaseIO> getIO() const { return m_io; }

/**
* @brief Check that the object exists
* @return Bool indicating whether the object exists in the file
*/
inline bool exists() const
{
switch (OTYPE) {
case StorageObjectType::Dataset: {
return m_io->objectExists(m_path);
}
case StorageObjectType::Attribute: {
return m_io->attributeExists(m_path);
}
default: {
throw std::runtime_error("Unsupported StorageObjectType");
}
}
}

/**
* @brief Reads a dataset and determines the data type.
*
Expand Down
6 changes: 6 additions & 0 deletions src/io/hdf5/HDF5IO.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -757,6 +757,12 @@ bool HDF5IO::objectExists(const std::string& path)
}
}

bool HDF5IO::attributeExists(const std::string& path)
{
auto attributePtr = this->getAttribute(path);
return (attributePtr != nullptr);
}

std::unique_ptr<AQNWB::IO::BaseRecordingData> HDF5IO::getDataSet(
const std::string& path)
{
Expand Down
10 changes: 10 additions & 0 deletions src/io/hdf5/HDF5IO.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -283,6 +283,16 @@ class HDF5IO : public BaseIO
*/
bool objectExists(const std::string& path) override;

/**
* @brief Checks whether an Attribute exists at the
* location in the file.
* @param path The location of the attribute in the file. I.e.,
* this is a combination of that parent object's
* path and the name of the attribute.
* @return Whether the attribute exists.
*/
bool attributeExists(const std::string& path) override;

/**
* @brief Returns the HDF5 type of object at a given path.
* @param path The location in the file of the object.
Expand Down
4 changes: 4 additions & 0 deletions tests/examples/test_ecephys_data_read.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -90,6 +90,10 @@ TEST_CASE("ElectricalSeriesReadExample", "[ecephys]")
auto readDataWrapper = electricalSeries->dataLazy<float>();
// [example_read_get_data_wrapper_snippet]

// [example_read_check_data_exists_snippet]
REQUIRE(readDataWrapper->exists());
// [example_read_check_data_exists_snippet]

// [example_read_get_datablock_snippet]
// Read the full ElectricalSeries.data back
DataBlock<float> dataValues = readDataWrapper->values();
Expand Down
3 changes: 3 additions & 0 deletions tests/testHDF5IO.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -254,6 +254,7 @@ TEST_CASE("writeAttributes", "[hdf5io]")

hdf5io.createAttribute(
BaseDataType::I32, &data, "/data", "array", dataSize);
REQUIRE(hdf5io.attributeExists("/data/array"));
}

// string array
Expand All @@ -262,13 +263,15 @@ TEST_CASE("writeAttributes", "[hdf5io]")
const std::vector<std::string> data = {"col1", "col2", "col3"};

hdf5io.createAttribute(data, "/data", "string_array");
REQUIRE(hdf5io.attributeExists("/data/string_array"));
}

// soft link
SECTION("link")
{
std::vector<std::string> data;
hdf5io.createLink("/data/link", "linked_data");
REQUIRE(hdf5io.objectExists("/data/link"));
}

// reference
Expand Down

0 comments on commit aad6928

Please sign in to comment.