diff --git a/Framework/API/inc/MantidAPI/MultipleFileProperty.h b/Framework/API/inc/MantidAPI/MultipleFileProperty.h index 0d018416d5e7a756629d2168d041465ed6d34fdf..19e83a87a89a688ae5a59cdc32788b1210d3762a 100644 --- a/Framework/API/inc/MantidAPI/MultipleFileProperty.h +++ b/Framework/API/inc/MantidAPI/MultipleFileProperty.h @@ -129,21 +129,22 @@ namespace API { class DLLExport MultipleFileProperty : public Kernel::PropertyWithValue<std::vector<std::vector<std::string>>> { public: - /// Constructor + MultipleFileProperty( + const std::string &name, unsigned int action, + const std::vector<std::string> &exts = std::vector<std::string>()); + MultipleFileProperty( const std::string &name, const std::vector<std::string> &exts = std::vector<std::string>()); - /// 'Virtual copy constructor MultipleFileProperty *clone() const override { return new MultipleFileProperty(*this); } - /// Overridden functions to accomodate std::vector<std::vector<std::string>>> - /// structure of this property. std::string setValue(const std::string &propValue) override; std::string value() const override; std::string getDefault() const override; + bool isOptional() const; /// @return the vector of suggested extensions. For use in GUIs showing files. std::vector<std::string> getExts() const { return m_exts; } @@ -156,6 +157,8 @@ public: operator=; private: + /// Returns a string depending on whether an empty value is valid + std::string isEmptyValueValid() const; std::string setValueAsSingleFile(const std::string &propValue); std::string setValueAsMultipleFiles(const std::string &propValue); /// Whether or not the user has turned on multifile loading. @@ -168,6 +171,9 @@ private: /// The default file extension associated with the type of file this property /// will handle std::string m_defaultExt; + /// The action type of this property + /// Load (dafault) or OptionalLoad are supported + unsigned int m_action; }; } // namespace API diff --git a/Framework/API/src/MultipleFileProperty.cpp b/Framework/API/src/MultipleFileProperty.cpp index 0316d3507fd9aae2664fde98b6429410d919660a..a961771273cf7a3afdb4243b50f47c407e2e7ebf 100644 --- a/Framework/API/src/MultipleFileProperty.cpp +++ b/Framework/API/src/MultipleFileProperty.cpp @@ -37,17 +37,27 @@ bool doesNotContainWildCard(const std::string &ext) { namespace Mantid { namespace API { /** - * Constructor + * Alternative constructor with action * - * @param name :: The name of the property - * @param exts :: The allowed/suggested extensions + * @param name :: The name of the property + * @param action :: File action + * @param exts :: The allowed/suggested extensions */ MultipleFileProperty::MultipleFileProperty(const std::string &name, + unsigned int action, const std::vector<std::string> &exts) : PropertyWithValue<std::vector<std::vector<std::string>>>( name, std::vector<std::vector<std::string>>(), - boost::make_shared<MultiFileValidator>(exts), Direction::Input), - m_multiFileLoadingEnabled(), m_exts(), m_parser(), m_defaultExt("") { + boost::make_shared<MultiFileValidator>( + exts, (action == FileProperty::Load)), + Direction::Input) { + if (action != FileProperty::Load && action != FileProperty::OptionalLoad) { + /// raise error for unsupported actions + throw std::runtime_error( + "Specified action is not supported for MultipleFileProperty"); + } else { + m_action = action; + } std::string allowMultiFileLoading = Kernel::ConfigService::Instance().getString("loading.multifile"); @@ -61,6 +71,35 @@ MultipleFileProperty::MultipleFileProperty(const std::string &name, m_exts.push_back(ext); } +/** + * Default constructor with default action + * + * @param name :: The name of the property + * @param exts :: The allowed/suggested extensions + */ +MultipleFileProperty::MultipleFileProperty(const std::string &name, + const std::vector<std::string> &exts) + : MultipleFileProperty(name, FileProperty::Load, exts) {} + +/** +* Check if this property is optional +* @returns True if the property is optinal, false otherwise +*/ +bool MultipleFileProperty::isOptional() const { + return (m_action == FileProperty::OptionalLoad); +} + +/** + * @returns Empty string if empty value is valid, error message otherwise + */ +std::string MultipleFileProperty::isEmptyValueValid() const { + if (isOptional()) { + return ""; + } else { + return "No file specified."; + } +} + /** * Convert the given propValue into a comma and plus separated list of full *filenames, and pass to the parent's @@ -74,8 +113,11 @@ MultipleFileProperty::MultipleFileProperty(const std::string &name, *An empty string indicates success. */ std::string MultipleFileProperty::setValue(const std::string &propValue) { - // No empty value is allowed. - if (propValue.empty()) + // No empty value is allowed, unless optional. + // This is yet aditional check that is beyond the underlying + // MultiFileValidator, + // so isOptional needs to be inspected here as well + if (propValue.empty() && !isOptional()) return "No file(s) specified."; // If multiple file loading is disabled, then set value assuming it is a diff --git a/Framework/API/test/MultipleFilePropertyTest.h b/Framework/API/test/MultipleFilePropertyTest.h index 67fa5c0034df099b04f4b8d0f9e156925833ad81..2aaa8ff37fdc6235e2b858c3f91cbc44c615385e 100644 --- a/Framework/API/test/MultipleFilePropertyTest.h +++ b/Framework/API/test/MultipleFilePropertyTest.h @@ -1,6 +1,7 @@ #ifndef MANTID_API_MULTIPLEFILEPROPERTYTEST_H_ #define MANTID_API_MULTIPLEFILEPROPERTYTEST_H_ +#include "MantidAPI/FileProperty.h" #include "MantidAPI/MultipleFileProperty.h" #include "MantidKernel/System.h" #include "MantidKernel/Timer.h" @@ -17,6 +18,7 @@ using namespace Mantid; using namespace Mantid::API; +using Mantid::API::FileProperty; ////////////////////////////////////////////////////////////////////////////////////////////// // Helper functions. @@ -616,6 +618,18 @@ public: TS_ASSERT_EQUALS(fileNames[0].size(), 1); } + void test_multiFileOptionalLoad() { + MultipleFileProperty p("Filename", FileProperty::OptionalLoad); + p.setValue("myJunkFile.nxs"); + TS_ASSERT(p.isValid().empty()); + } + + void test_multiFileOptionalLoadEmpty() { + MultipleFileProperty p("Filename", FileProperty::OptionalLoad); + p.setValue(""); + TS_ASSERT(p.isValid().empty()); + } + private: ////////////////////////////////////////////////////////////////////////////////////////////// // Private helper functions. diff --git a/Framework/Kernel/inc/MantidKernel/MultiFileValidator.h b/Framework/Kernel/inc/MantidKernel/MultiFileValidator.h index 889bdd23cbbbfff91f5913a10aea300e0106e23d..ed6343d8579e2c4d0d6492721af5f06ad830f9b8 100644 --- a/Framework/Kernel/inc/MantidKernel/MultiFileValidator.h +++ b/Framework/Kernel/inc/MantidKernel/MultiFileValidator.h @@ -47,7 +47,8 @@ class MANTID_KERNEL_DLL MultiFileValidator public: MultiFileValidator(); MultiFileValidator(const MultiFileValidator &mfv); - explicit MultiFileValidator(const std::vector<std::string> &extensions); + explicit MultiFileValidator(const std::vector<std::string> &extensions, + bool testFilesExist = true); IValidator_sptr clone() const override; diff --git a/Framework/Kernel/src/MultiFileValidator.cpp b/Framework/Kernel/src/MultiFileValidator.cpp index 9ec875f27a31ef60c42230030032dac19b06ef60..705b87b6e8c6add62cad9c12895e2350db5ca5f1 100644 --- a/Framework/Kernel/src/MultiFileValidator.cpp +++ b/Framework/Kernel/src/MultiFileValidator.cpp @@ -21,11 +21,12 @@ MultiFileValidator::MultiFileValidator(const MultiFileValidator &mfv) /** Constructor * @param extensions :: The permitted file extensions (e.g. .RAW) + * @param testFilesExist :: If to check if files exist */ MultiFileValidator::MultiFileValidator( - const std::vector<std::string> &extensions) + const std::vector<std::string> &extensions, bool testFilesExist) : TypedValidator<std::vector<std::vector<std::string>>>(), - m_fileValidator(extensions, true) {} + m_fileValidator(extensions, testFilesExist) {} /// Returns the set of valid values std::vector<std::string> MultiFileValidator::allowedValues() const { diff --git a/Framework/Kernel/test/MultiFileValidatorTest.h b/Framework/Kernel/test/MultiFileValidatorTest.h index bd2e0b3332b955d51d5ecb6bf37259de8fdb36f7..38ceddad9fe0e341601c326b0899bae0254667d4 100644 --- a/Framework/Kernel/test/MultiFileValidatorTest.h +++ b/Framework/Kernel/test/MultiFileValidatorTest.h @@ -125,6 +125,20 @@ public: file_val.isValid(std::vector<std::vector<std::string>>()).empty(), false); } + + void testFailsOnNonExistingFiles() { + std::vector<std::string> vec{"foo"}; + MultiFileValidator file_val(vec); + std::vector<std::vector<std::string>> file{{"myJunkFile.foo"}}; + TS_ASSERT(!file_val.isValid(file).empty()); + } + + void testPassesOnNonExistingFiles() { + std::vector<std::string> vec{"foo"}; + MultiFileValidator file_val(vec, false); + std::vector<std::vector<std::string>> file{{"myJunkFile.foo"}}; + TS_ASSERT(file_val.isValid(file).empty()); + } }; #endif /*MULTIFILEVALIDATORTEST_H_*/ diff --git a/Framework/PythonInterface/mantid/api/src/Exports/MultipleFileProperty.cpp b/Framework/PythonInterface/mantid/api/src/Exports/MultipleFileProperty.cpp index 994b1a98c51c1199261424f27d62d2d7eac6c2ae..2ffd86de5fbf9ebdc7be404d06a49bd01c54d620 100644 --- a/Framework/PythonInterface/mantid/api/src/Exports/MultipleFileProperty.cpp +++ b/Framework/PythonInterface/mantid/api/src/Exports/MultipleFileProperty.cpp @@ -1,3 +1,4 @@ +#include "MantidAPI/FileProperty.h" #include "MantidAPI/MultipleFileProperty.h" #include "MantidPythonInterface/kernel/Converters/PySequenceToVector.h" #include "MantidPythonInterface/kernel/IsNone.h" @@ -7,6 +8,7 @@ #include <boost/python/make_constructor.hpp> #include <boost/python/str.hpp> +using Mantid::API::FileProperty; using Mantid::API::MultipleFileProperty; using Mantid::Kernel::PropertyWithValue; using Mantid::PythonInterface::Converters::PySequenceToVector; @@ -45,8 +47,9 @@ boost::python::object valueAsPyObject(MultipleFileProperty &self) { } MultipleFileProperty * -createMultipleFileProperty(const std::string &name, - const object &extensions = object()) { +createMultipleFilePropertyWithAction(const std::string &name, + unsigned int action, + const object &extensions = object()) { std::vector<std::string> extsAsVector; if (!Mantid::PythonInterface::isNone(extensions)) { extract<std::string> extractor(extensions); @@ -56,7 +59,14 @@ createMultipleFileProperty(const std::string &name, extsAsVector = PySequenceToVector<std::string>(extensions)(); } } - return new MultipleFileProperty(name, extsAsVector); + return new MultipleFileProperty(name, action, extsAsVector); +} + +MultipleFileProperty * +createMultipleFileProperty(const std::string &name, + const object &extensions = object()) { + return createMultipleFilePropertyWithAction( + name, FileProperty::FileAction::Load, extensions); } } @@ -70,6 +80,10 @@ void export_MultipleFileProperty() { .def("__init__", make_constructor( &createMultipleFileProperty, default_call_policies(), (arg("name"), arg("extensions") = object()))) + .def("__init__", + make_constructor( + &createMultipleFilePropertyWithAction, default_call_policies(), + (arg("name"), arg("action"), arg("extensions") = object()))) // Override the base class one to do something more appropriate .add_property("value", &valueAsPyObject); } diff --git a/docs/source/concepts/Properties.rst b/docs/source/concepts/Properties.rst index 34aaf5344ef1e1fdfab914d392ef5facf4eedcea..4c76dbef8607a6a6e8e975e6f9ef602005d19cb2 100644 --- a/docs/source/concepts/Properties.rst +++ b/docs/source/concepts/Properties.rst @@ -50,8 +50,9 @@ or, if creating using an already existing vector: File Properties ~~~~~~~~~~~~~~~ -These properties are for capturing and holding the path and filename to -an external file. File properties have a FileAction property that +There are two file properties: ``FileProperty`` and ``MultipleFileProperty``. +These properties are for capturing and holding the path and filenames to +external file (s). File properties have a FileAction property that controls it's purpose and behaviour. Save :to specify a file to write to, the file may or may not exist @@ -65,6 +66,8 @@ If the file property is has a FileAction of Load as is given a relative path (such as "input.txt" or "\\data\\input.txt" as its value it will search for matching files in this order: +Note, that ``MultipleFileProperty`` supports only Load (default) and OptionalLoad actions. + #. The current directory #. The entries in order from the datasearch.directories entry in the :ref:`Properties File <Properties File>` @@ -158,6 +161,8 @@ The validators currently included in Mantid are: set of values. - FileValidator - ensures that a file (given as a string property) exists (used internally by the FileProperty). +- MultiFileValidator - ensures that each file in a given list exists + (used internally by the MultipleFileProperty). In addition, there are a number of validators specifically for use with Workspace properties: diff --git a/docs/source/release/v3.8.0/framework.rst b/docs/source/release/v3.8.0/framework.rst index 7915a76b8c7755c53d2de581646da4203be89b2f..00700320acbd83685b73a2b34e11fa029ce4df49 100644 --- a/docs/source/release/v3.8.0/framework.rst +++ b/docs/source/release/v3.8.0/framework.rst @@ -23,6 +23,8 @@ Concepts undefined and infinite values and errors will be zeroed. - ``Lattice`` : Allow setting a UB matrix with negative determinant (improper rotation) +- ``MultipleFileProperty`` : will now support also ``OptionalLoad`` ``FileAction`` (similar to ``FileProperty``). + Algorithms ----------