diff --git a/lib/src/Base/Common/ResourceMap.cxx b/lib/src/Base/Common/ResourceMap.cxx index f83adfe08b..15b5604ecc 100644 --- a/lib/src/Base/Common/ResourceMap.cxx +++ b/lib/src/Base/Common/ResourceMap.cxx @@ -27,6 +27,7 @@ #include "openturns/Path.hxx" #include "openturns/Collection.hxx" #include "openturns/XMLToolbox.hxx" + #ifdef OPENTURNS_HAVE_LIBXML2 #include #endif @@ -195,6 +196,11 @@ void ResourceMap::AddAsString(const String & key, const String & value) GetInstance().lock().addAsString(key, value); } +void ResourceMap::AddAsStringEnum(const String & key, const String & value, const std::vector & enumValues) +{ + GetInstance().lock().addAsStringEnum(key, value, enumValues); +} + void ResourceMap::AddAsBool(const String & key, const Bool value) { GetInstance().lock().addAsBool(key, value); @@ -326,7 +332,11 @@ void ResourceMap::removeKey(const String & key) const String keyType(getType(key)); if (keyType == "str") + { mapString_.erase(mapString_.find(key)); + if (mapStringEnum_.find(key) != mapStringEnum_.end()) + mapStringEnum_.erase(mapStringEnum_.find(key)); + } else if (keyType == "float") mapScalar_.erase(mapScalar_.find(key)); else if (keyType == "int") @@ -453,6 +463,14 @@ void ResourceMap::setAsString(const String & key, const String & value) const MapStringType::iterator it = mapString_.find(key); if (it == mapString_.end()) throw InternalException(HERE) << "Key '" << key << "' is missing in ResourceMap as a String."; + const MapStringEnumType::iterator it2 = mapStringEnum_.find(key); + if (it2 != mapStringEnum_.end() && std::find(it2->second.begin(), it2->second.end(), value) == it2->second.end()) + { + String possibleValues; + for (std::vector::iterator it3 = it2->second.begin(); it3 != it2->second.end(); ++ it3) + possibleValues += *it3 + ", "; + throw InvalidArgumentException(HERE) << "Value for key '" << key << "' must be one of: " << possibleValues << " got '" << value << "'"; + } it->second = value; } @@ -487,6 +505,16 @@ void ResourceMap::addAsString(const String & key, const String & value) mapString_[key] = value; } +void ResourceMap::addAsStringEnum(const String & key, const String & value, const std::vector & enumValues) +{ + if (mapString_.find(key) != mapString_.end()) + throw InternalException(HERE) << "Key '" << key << "' is already in ResourceMap as a String."; + mapString_[key] = value; + if (std::find(enumValues.begin(), enumValues.end(), value) == enumValues.end()) + throw InternalException(HERE) << "Enum values do not contain value '" << value << "'"; + mapStringEnum_[key] = enumValues; +} + void ResourceMap::addAsBool(const String & key, const Bool value) { if (mapBool_.find(key) != mapBool_.end()) @@ -718,7 +746,7 @@ void ResourceMap::loadDefaultConfiguration() addAsUnsignedInteger("Contour-DefaultLevelsNumber", 10); addAsBool("Contour-DefaultIsFilled", false); addAsBool("Contour-DefaultDrawLabels", true); - addAsString("Contour-DefaultColorMapNorm", "linear"); + addAsStringEnum("Contour-DefaultColorMapNorm", "linear", {"asinh", "linear", "log", "logit", "symlog", "rank"}); addAsString("Contour-DefaultColorMap", "viridis"); addAsString("Contour-DefaultColorBarPosition", "right"); addAsString("Contour-DefaultExtend", "both"); diff --git a/lib/src/Base/Common/openturns/ResourceMap.hxx b/lib/src/Base/Common/openturns/ResourceMap.hxx index 0549e4ccc3..e393bd82e3 100644 --- a/lib/src/Base/Common/openturns/ResourceMap.hxx +++ b/lib/src/Base/Common/openturns/ResourceMap.hxx @@ -65,6 +65,7 @@ public: /** Add a value in the maps */ static void AddAsString(const String & key, const String & value); + static void AddAsStringEnum(const String & key, const String & value, const std::vector & enumValues); static void AddAsBool(const String & key, const Bool value); static void AddAsUnsignedInteger(const String & key, const UnsignedInteger value); static void AddAsScalar(const String & key, const Scalar value); @@ -220,6 +221,7 @@ protected: * @param value The value written to a string */ void addAsString(const String & key, const String & value); + void addAsStringEnum(const String & key, const String & value, const std::vector & enumValues); /** Method for adding information into the resource map * @param key The name under which the value is stored in the ResourceMap @@ -280,11 +282,13 @@ private: typedef std::map< String, Scalar > MapScalarType; typedef std::map< String, UnsignedInteger > MapUnsignedIntegerType; typedef std::map< String, Bool > MapBoolType; + typedef std::map< String, std::vector< String > > MapStringEnumType; MapStringType mapString_; MapScalarType mapScalar_; MapUnsignedIntegerType mapUnsignedInteger_; MapBoolType mapBool_; + MapStringEnumType mapStringEnum_; friend struct ResourceMap_init; }; /* class ResourceMap */ diff --git a/python/src/ResourceMap_doc.i.in b/python/src/ResourceMap_doc.i.in index a97b3785f4..b63a57d2de 100644 --- a/python/src/ResourceMap_doc.i.in +++ b/python/src/ResourceMap_doc.i.in @@ -234,6 +234,30 @@ Examples // --------------------------------------------------------------------- +%feature("docstring") OT::ResourceMap::AddAsStringEnum +"Add a new string enum parameter. + +Similar to :meth:`AddAsString` except :meth:`SetAsString` calls will make sure the +value associated to that key is part of the list of possible supplied values. + +Parameters +---------- +key : str + An identifier associated to the parameter. +value : str + The value associated to that key. The key is added to the string map even if + it already exists in another map (float, int or bool). +enumValues : sequence of str + Possible values + +Examples +-------- +>>> import openturns as ot +>>> ot.ResourceMap.AddAsStringEnum('View-ImageFormat3', 'png', ['png', 'jpg', 'bmp']) +>>> ot.ResourceMap.RemoveKey('View-ImageFormat3')" + +// --------------------------------------------------------------------- + %feature("docstring") OT::ResourceMap::GetAsString "Access a string parameter. diff --git a/python/test/t_ResourceMap_missing.py b/python/test/t_ResourceMap_missing.py index cd8ba3b006..72b956bbe7 100755 --- a/python/test/t_ResourceMap_missing.py +++ b/python/test/t_ResourceMap_missing.py @@ -13,9 +13,10 @@ resourcemap_lines += f.read().splitlines() resourcemap_content = {} for line in resourcemap_lines: - match = re.search(r'addAs(\w+)\("([\w\-]+)",[ ]*([\w\d\.\-\"]+)\);', line) + match = re.search(r'addAs(\w+)\("([\w\-]+)",[ ]*([\w\d\.\-\"]+)[\),]', line) if match is not None: key, vtype, value = match.group(2), match.group(1), match.group(3) + print(key, vtype, value) if key == "SymbolicParser-Backend": continue if vtype == "Scalar": @@ -24,7 +25,7 @@ resourcemap_content[key] = int(value) elif vtype == "Bool": resourcemap_content[key] = {"true": True, "false": False}[value] - elif vtype == "String": + elif vtype.startswith("String"): resourcemap_content[key] = value.strip('"') else: raise ValueError(f"got {key}")