Skip to content

Commit 0d87c9b

Browse files
committed
Refactor so that log warning only appears once per operation.
1 parent 3f02334 commit 0d87c9b

File tree

3 files changed

+77
-54
lines changed

3 files changed

+77
-54
lines changed

Framework/API/inc/MantidAPI/AnalysisDataService.h

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -82,8 +82,10 @@ class MANTID_API_DLL AnalysisDataServiceImpl final : public Kernel::DataService<
8282
//@}
8383

8484
public:
85-
/// Is the given name a valid name for an object in the ADS
86-
const std::string isValid(const std::string &name) const;
85+
/// Validate the name and issue a warning in release mode, only return error string in debug mode.
86+
const std::string isValid(const std::string &name, const bool printWarning = false) const;
87+
//// Check whether the name is a valid python variable name and return an error message if not.
88+
const std::string validateName(const std::string &name) const;
8789
/// Overridden add member to attach the name to the workspace when a
8890
/// workspace object is added to the service
8991
void add(const std::string &name, const std::shared_ptr<API::Workspace> &workspace) override;

Framework/API/src/AnalysisDataService.cpp

Lines changed: 34 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -32,28 +32,26 @@ std::shared_ptr<const WorkspaceGroup> AnalysisDataServiceImpl::GroupUpdatedNotif
3232
// Public methods
3333
//-------------------------------------------------------------------------
3434
/**
35-
* Is the given name a valid name for an object in the ADS?
35+
* Check whether the name is valid for the ADS. In release mode, issue a warning but do not return the error.
36+
* In debug mode, return the error string.
3637
* @param name A string containing a possible name for an object in the ADS
3738
* @return An empty string if the name is valid or an error message stating the
3839
* problem if the name is unacceptable.
3940
*/
40-
const std::string AnalysisDataServiceImpl::isValid(const std::string &name) const {
41-
std::regex validName("^[a-zA-Z_][\\w]*");
42-
43-
if (!std::regex_match(name, validName)) {
44-
const std::string error =
45-
"Invalid object name '" + name +
46-
"'. Names must start with a letter or underscore and contain only alpha-numeric characters and underscores.";
47-
48-
// Log a warning message to let user know we will stop allowing invalid variable names in the future.
49-
const std::string warningMessage =
50-
error + "\n"
51-
"Currently this is only a warning, but in a future version of Mantid this will raise an exception and "
52-
"the operation will fail.\n"
53-
"Please update your scripts to use valid Python identifiers for workspace names.";
54-
Kernel::Logger log("AnalaysisDataService");
55-
log.warning(warningMessage);
56-
41+
const std::string AnalysisDataServiceImpl::isValid(const std::string &name, const bool printWarning) const {
42+
const auto error = validateName(name);
43+
if (!error.empty()) {
44+
if (printWarning) {
45+
// Log a warning message to let user know we will stop allowing invalid variable names in the future.
46+
const std::string warningMessage =
47+
error +
48+
"\n"
49+
"Currently this is only a warning, but in a future version of Mantid this will raise an exception and "
50+
"the operation will fail.\n"
51+
"Please update your scripts to use valid Python identifiers for workspace names.";
52+
Kernel::Logger log("AnalaysisDataService");
53+
log.warning(warningMessage);
54+
}
5755
// Fail in debug mode if name is not valid.
5856
#ifndef NDEBUG
5957
return error;
@@ -63,6 +61,23 @@ const std::string AnalysisDataServiceImpl::isValid(const std::string &name) cons
6361
return "";
6462
}
6563

64+
/**
65+
* Check whether the name is a valid python variable name, i.e. starts with underscore or letter, and contains
66+
* only "word" characters (numbers, letters, underscores).
67+
* @param name A string containing the name to validate
68+
* @return An empty string if the name is valid or an error message describing the problem with the name.
69+
*/
70+
const std::string AnalysisDataServiceImpl::validateName(const std::string &name) const {
71+
std::regex validName("^[a-zA-Z_][\\w]*");
72+
std::string error = "";
73+
if (!std::regex_match(name, validName)) {
74+
error =
75+
"Invalid object name '" + name +
76+
"'. Names must start with a letter or underscore and contain only alpha-numeric characters and underscores.";
77+
}
78+
return error;
79+
}
80+
6681
/**
6782
* Overwridden add member to attach the name to the workspace when a workspace
6883
* object is added to the service
@@ -404,9 +419,8 @@ AnalysisDataServiceImpl::AnalysisDataServiceImpl()
404419
* valid then it will check it's container for the same name that is passed if
405420
* true throws std::runtime_error else nothing.
406421
*/
407-
408422
void AnalysisDataServiceImpl::verifyName(const std::string &name, const std::shared_ptr<API::WorkspaceGroup> &group) {
409-
const std::string error = isValid(name);
423+
const std::string error = isValid(name, true);
410424
if (!error.empty()) {
411425
throw std::invalid_argument(error);
412426
}

Framework/API/test/AnalysisDataServiceTest.h

Lines changed: 39 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -42,36 +42,36 @@ class AnalysisDataServiceTest : public CxxTest::TestSuite {
4242

4343
void setUp() override { ads.clear(); }
4444

45-
void testIsValidReturnsEmptyStringForValidPythonNames() {
46-
TS_ASSERT_EQUALS(ads.isValid("a"), "");
47-
TS_ASSERT_EQUALS(ads.isValid("Z"), "");
48-
TS_ASSERT_EQUALS(ads.isValid("camelCase"), "");
49-
TS_ASSERT_EQUALS(ads.isValid("PascalCase"), "");
50-
TS_ASSERT_EQUALS(ads.isValid("has_Underscore"), "");
51-
TS_ASSERT_EQUALS(ads.isValid("_starts_with_underscore"), "");
52-
TS_ASSERT_EQUALS(ads.isValid("ends_with_underscore_"), "");
53-
TS_ASSERT_EQUALS(ads.isValid("__l_o_t_s__o_f__u_n_d_e_r_s_c_o_r_e_s__"), "");
54-
TS_ASSERT_EQUALS(ads.isValid("alllowercase"), "");
55-
TS_ASSERT_EQUALS(ads.isValid("ALLUPPERCASE"), "");
56-
TS_ASSERT_EQUALS(ads.isValid("Numb3rs"), "");
57-
TS_ASSERT_EQUALS(ads.isValid("_m0r3_numb3r5"), "");
58-
TS_ASSERT_EQUALS(ads.isValid("_"), "");
59-
TS_ASSERT_EQUALS(ads.isValid("___"), "");
60-
}
61-
62-
void testIsValidReturnsErrorStringForNamesContainingIllegalCharacters() {
45+
void testValidateNameReturnsEmptyStringForValidPythonNames() {
46+
TS_ASSERT_EQUALS(ads.validateName("a"), "");
47+
TS_ASSERT_EQUALS(ads.validateName("Z"), "");
48+
TS_ASSERT_EQUALS(ads.validateName("camelCase"), "");
49+
TS_ASSERT_EQUALS(ads.validateName("PascalCase"), "");
50+
TS_ASSERT_EQUALS(ads.validateName("has_Underscore"), "");
51+
TS_ASSERT_EQUALS(ads.validateName("_starts_with_underscore"), "");
52+
TS_ASSERT_EQUALS(ads.validateName("ends_with_underscore_"), "");
53+
TS_ASSERT_EQUALS(ads.validateName("__l_o_t_s__o_f__u_n_d_e_r_s_c_o_r_e_s__"), "");
54+
TS_ASSERT_EQUALS(ads.validateName("alllowercase"), "");
55+
TS_ASSERT_EQUALS(ads.validateName("ALLUPPERCASE"), "");
56+
TS_ASSERT_EQUALS(ads.validateName("Numb3rs"), "");
57+
TS_ASSERT_EQUALS(ads.validateName("_m0r3_numb3r5"), "");
58+
TS_ASSERT_EQUALS(ads.validateName("_"), "");
59+
TS_ASSERT_EQUALS(ads.validateName("___"), "");
60+
}
61+
62+
void testValidateNameReturnsErrorStringForNamesContainingIllegalCharacters() {
6363
const std::string illegalChars = " +-/*\\%<>&|^~=!@()[]{},:.`$'\"?";
6464
for (const char &illegalChar : illegalChars) {
6565
const std::string illegalName = std::string("variable_name") + illegalChar;
6666
std::string expectedError =
6767
"Invalid object name '" + illegalName +
6868
"'. Names must start with a letter or underscore and contain only alpha-numeric characters and underscores.";
69-
TS_ASSERT_EQUALS(ads.isValid(illegalName), expectedError);
69+
TS_ASSERT_EQUALS(ads.validateName(illegalName), expectedError);
7070
}
7171
}
7272

73-
void testIsValidReturnsErrorStringForNamesStartingWithNumbers() {
74-
TS_ASSERT_EQUALS(ads.isValid("7dodgy_name"),
73+
void testValidateNameReturnsErrorStringForNamesStartingWithNumbers() {
74+
TS_ASSERT_EQUALS(ads.validateName("7dodgy_name"),
7575
"Invalid object name '7dodgy_name'. Names must start with a letter or underscore and contain only "
7676
"alpha-numeric characters and underscores.");
7777
}
@@ -151,13 +151,9 @@ class AnalysisDataServiceTest : public CxxTest::TestSuite {
151151
TS_ASSERT_THROWS_NOTHING(ads.remove(name));
152152
}
153153

154-
void test_Add_With_Name_Containing_Illegal_Characters_Throws_Invalid_Argument() {
155-
this->doAddingOnInvalidNameTests(false /*Don't use replace*/);
156-
}
154+
void testAddWithInvalidName() { this->doAddingOnInvalidNameTests(false /*Don't use replace*/); }
157155

158-
void test_AddOrReplace_With_Name_Containing_Illegal_Characters_Throws_Invalid_Argument() {
159-
this->doAddingOnInvalidNameTests(true /*Use replace*/);
160-
}
156+
void testAddOrReplaceWithInvalidName() { this->doAddingOnInvalidNameTests(true /*Use replace*/); }
161157

162158
void test_AddOrReplace_Does_Not_Throw_When_Adding_Object_That_Has_A_Name_That_Already_Exists() {
163159
const std::string name("MySpaceAddOrReplace");
@@ -542,18 +538,29 @@ class AnalysisDataServiceTest : public CxxTest::TestSuite {
542538
for (const char &illegalChar : illegalChars) {
543539
// Build illegal name
544540
std::string name = std::string("ws") + illegalChar + "name";
545-
// Add it
541+
542+
#ifndef NDEBUG
543+
// In debug mode, illegal workspace names throw exceptions.
546544
std::string errorMsg =
547545
std::string("Expected ADS to throw with illegal character ") + illegalChar + " in workspace name.";
548546
if (replace) {
549547
TSM_ASSERT_THROWS(errorMsg, addToADS(name), const std::invalid_argument &);
550548
} else {
551549
TSM_ASSERT_THROWS(errorMsg, addOrReplaceToADS(name), const std::invalid_argument &);
552550
}
553-
bool stored = ads.doesExist(name);
554-
TS_ASSERT_EQUALS(stored, false);
555-
if (stored)
556-
ads.remove(name); // Clear up if the test fails so that it dones't impact on others.
551+
TS_ASSERT(!ads.doesExist(name));
552+
#else
553+
// In release mode, a warning is printed but no exception is thrown.
554+
std::string errorMsg =
555+
std::string("Expected ADS not to throw with illegal character ") + illegalChar + " in workspace name.";
556+
if (replace) {
557+
TSM_ASSERT_THROWS_NOTHING(errorMsg, addToADS(name));
558+
} else {
559+
TSM_ASSERT_THROWS_NOTHING(errorMsg, addOrReplaceToADS(name));
560+
}
561+
TS_ASSERT(ads.doesExist(name));
562+
#endif
563+
ads.remove(name); // Clear up if the test fails so that it dones't impact on others.
557564
}
558565
}
559566

0 commit comments

Comments
 (0)