This is an automated email from the ASF dual-hosted git repository.
martinzink pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/nifi-minifi-cpp.git
The following commit(s) were added to refs/heads/main by this push:
new 2f7ce29bc MINIFICPP-2862 Add StandardValidator::NUMBER_VALIDATOR
(#2232)
2f7ce29bc is described below
commit 2f7ce29bc5fdb913389f650db0388195e8a13d12
Author: Martin Zink <[email protected]>
AuthorDate: Sat Aug 8 20:26:30 2026 +0200
MINIFICPP-2862 Add StandardValidator::NUMBER_VALIDATOR (#2232)
---
.../ubuntu_22_04_clang_arm_manifest.json | 2 +-
core-framework/common/include/utils/ParsingUtils.h | 21 +++++-
core-framework/common/src/utils/ParsingUtils.cpp | 8 ---
.../include/api/utils/ProcessorConfigUtils.h | 2 +-
.../cpp-extension-lib/src/utils/minifi-c-utils.cpp | 3 +
.../include/utils/ProcessorConfigUtils.h | 14 +++-
.../llamacpp/processors/RunLlamaCppInference.h | 1 +
.../llamacpp/tests/RunLlamaCppInferenceTests.cpp | 4 --
extensions/python/ExecutePythonProcessor.cpp | 5 +-
.../python/pythonprocessors/nifiapi/properties.py | 6 ++
libminifi/src/minifi-api.cpp | 1 +
libminifi/test/unit/PropertyValidationTests.cpp | 12 ++++
.../include/minifi-cpp/core/PropertyValidator.h | 80 ++++++++++++----------
minifi-api/include/minifi-api.h | 1 +
14 files changed, 108 insertions(+), 52 deletions(-)
diff --git a/.github/references/ubuntu_22_04_clang_arm_manifest.json
b/.github/references/ubuntu_22_04_clang_arm_manifest.json
index e4589f803..87d17440d 100644
--- a/.github/references/ubuntu_22_04_clang_arm_manifest.json
+++ b/.github/references/ubuntu_22_04_clang_arm_manifest.json
@@ -5765,7 +5765,7 @@
"Min P": {
"name": "Min P",
"description": "Sets a minimum base probability
threshold for token selection. 0.0 = disabled.",
- "validator": "VALID",
+ "validator": "NUMBER_VALIDATOR",
"required": "false",
"sensitive": "false",
"expressionLanguageScope": "NONE"
diff --git a/core-framework/common/include/utils/ParsingUtils.h
b/core-framework/common/include/utils/ParsingUtils.h
index 33236eda8..85e18bde7 100644
--- a/core-framework/common/include/utils/ParsingUtils.h
+++ b/core-framework/common/include/utils/ParsingUtils.h
@@ -40,7 +40,8 @@ std::expected<uint64_t, std::error_code>
parseDataSize(std::string_view input);
std::expected<uint32_t, std::error_code>
parseUnixOctalPermissions(std::string_view input);
-std::expected<float, std::error_code> parseFloat(std::string_view input);
+template<std::floating_point T>
+std::expected<T, std::error_code> parseFloatingPoint(std::string_view input);
template<std::integral T>
std::expected<T, std::error_code> parseIntegralMinMax(const std::string_view
input, const T minimum, const T maximum) {
@@ -90,4 +91,22 @@ std::expected<T, std::error_code> parseEnum(const
std::string_view input) {
return *result;
}
+template<std::floating_point T>
+std::expected<T, std::error_code> parseFloatingPoint(const std::string_view
input) {
+ const auto trimmed_input = utils::string::trim(input);
+ T value{};
+
+ const auto [ptr, ec] = std::from_chars(trimmed_input.data(),
trimmed_input.data() + trimmed_input.size(), value);
+
+ if (ec != std::errc()) {
+ return std::unexpected{core::ParsingErrorCode::GeneralParsingError};
+ }
+
+ if (ptr != trimmed_input.data() + trimmed_input.size()) {
+ return std::unexpected{core::ParsingErrorCode::GeneralParsingError};
+ }
+
+ return value;
+}
+
} // namespace org::apache::nifi::minifi::parsing
diff --git a/core-framework/common/src/utils/ParsingUtils.cpp
b/core-framework/common/src/utils/ParsingUtils.cpp
index 922704b95..75f095ef2 100644
--- a/core-framework/common/src/utils/ParsingUtils.cpp
+++ b/core-framework/common/src/utils/ParsingUtils.cpp
@@ -126,12 +126,4 @@ std::expected<uint32_t, std::error_code>
parseUnixOctalPermissions(const std::st
return result;
}
-std::expected<float, std::error_code> parseFloat(std::string_view input) {
- try {
- return std::stof(std::string{input});
- } catch(const std::exception&) {
- return std::unexpected{core::ParsingErrorCode::GeneralParsingError};
- }
-}
-
} // namespace org::apache::nifi::minifi::parsing
diff --git
a/extension-framework/cpp-extension-lib/include/api/utils/ProcessorConfigUtils.h
b/extension-framework/cpp-extension-lib/include/api/utils/ProcessorConfigUtils.h
index 2ec9571ed..ea2c17d9e 100644
---
a/extension-framework/cpp-extension-lib/include/api/utils/ProcessorConfigUtils.h
+++
b/extension-framework/cpp-extension-lib/include/api/utils/ProcessorConfigUtils.h
@@ -134,7 +134,7 @@ inline std::optional<float>
parseOptionalFloatProperty(const core::ProcessContex
if (property_str->empty()) {
return std::nullopt;
}
- return parsing::parseFloat(*property_str)
+ return parsing::parseFloatingPoint<float>(*property_str)
| minifi::utils::orThrow(fmt::format("Expected parsable float from
\"{}\"", property.name));
}
return std::nullopt;
diff --git a/extension-framework/cpp-extension-lib/src/utils/minifi-c-utils.cpp
b/extension-framework/cpp-extension-lib/src/utils/minifi-c-utils.cpp
index e11fd8972..cf70d2c71 100644
--- a/extension-framework/cpp-extension-lib/src/utils/minifi-c-utils.cpp
+++ b/extension-framework/cpp-extension-lib/src/utils/minifi-c-utils.cpp
@@ -55,6 +55,9 @@ minifi_validator toStandardPropertyValidator(const
minifi::core::PropertyValidat
if (validator->getEquivalentNifiStandardValidatorName() ==
minifi::core::StandardPropertyValidators::PORT_VALIDATOR.getEquivalentNifiStandardValidatorName())
{
return MINIFI_VALIDATOR_PORT;
}
+ if (validator->getEquivalentNifiStandardValidatorName() ==
minifi::core::StandardPropertyValidators::NUMBER_VALIDATOR.getEquivalentNifiStandardValidatorName())
{
+ return MINIFI_VALIDATOR_NUMBER;
+ }
gsl_FailFast();
}
diff --git a/extension-framework/include/utils/ProcessorConfigUtils.h
b/extension-framework/include/utils/ProcessorConfigUtils.h
index b69ed40d9..3b15d0e92 100644
--- a/extension-framework/include/utils/ProcessorConfigUtils.h
+++ b/extension-framework/include/utils/ProcessorConfigUtils.h
@@ -55,6 +55,18 @@ inline int64_t parseI64Property(const core::ProcessContext&
ctx, const core::Pro
| orThrow(fmt::format("Expected parsable int64_t from \"{}\"",
property.name));
}
+inline double parseF64Property(const core::ProcessContext& ctx, const
core::PropertyReference& property, const core::FlowFile* flow_file = nullptr) {
+ return ctx.getProperty(property.name, flow_file)
+ | andThen(parsing::parseFloatingPoint<double>)
+ | orThrow(fmt::format("Expected parsable double from \"{}\"",
property.name));
+}
+
+inline float parseF32Property(const core::ProcessContext& ctx, const
core::PropertyReference& property, const core::FlowFile* flow_file = nullptr) {
+ return ctx.getProperty(property.name, flow_file)
+ | andThen(parsing::parseFloatingPoint<float>)
+ | orThrow(fmt::format("Expected parsable float from \"{}\"",
property.name));
+}
+
inline std::chrono::milliseconds parseDurationProperty(const
core::ProcessContext& ctx, const core::PropertyReference& property, const
core::FlowFile* flow_file = nullptr) {
return ctx.getProperty(property.name, flow_file)
| andThen(parsing::parseDuration<std::chrono::milliseconds>)
@@ -133,7 +145,7 @@ inline std::optional<float>
parseOptionalFloatProperty(const core::ProcessContex
if (property_str->empty()) {
return std::nullopt;
}
- return parsing::parseFloat(*property_str)
+ return parsing::parseFloatingPoint<float>(*property_str)
| utils::orThrow(fmt::format("Expected parsable float from \"{}\"",
property.name));
}
return std::nullopt;
diff --git a/extensions/llamacpp/processors/RunLlamaCppInference.h
b/extensions/llamacpp/processors/RunLlamaCppInference.h
index 16cf7a9c6..67cd14a9e 100644
--- a/extensions/llamacpp/processors/RunLlamaCppInference.h
+++ b/extensions/llamacpp/processors/RunLlamaCppInference.h
@@ -83,6 +83,7 @@ class RunLlamaCppInference : public api::core::ProcessorImpl {
.build();
EXTENSIONAPI static constexpr auto MinP =
core::PropertyDefinitionBuilder<>::createProperty("Min P")
.withDescription("Sets a minimum base probability threshold for token
selection. 0.0 = disabled.")
+ .withValidator(core::StandardPropertyValidators::NUMBER_VALIDATOR)
.build();
EXTENSIONAPI static constexpr auto MinKeep =
core::PropertyDefinitionBuilder<>::createProperty("Min Keep")
.withDescription("If greater than 0, force samplers to return N possible
tokens at minimum.")
diff --git a/extensions/llamacpp/tests/RunLlamaCppInferenceTests.cpp
b/extensions/llamacpp/tests/RunLlamaCppInferenceTests.cpp
index 3582c2190..fb2207521 100644
--- a/extensions/llamacpp/tests/RunLlamaCppInferenceTests.cpp
+++ b/extensions/llamacpp/tests/RunLlamaCppInferenceTests.cpp
@@ -233,10 +233,6 @@ TEST_CASE("Invalid values for optional double type
properties throw exception")
REQUIRE(controller.getProcessor()->setProperty(processors::RunLlamaCppInference::TopP.name,
"invalid_value"));
property_name = processors::RunLlamaCppInference::TopP.name;
}
- SECTION("Invalid value for Min P property") {
-
REQUIRE(controller.getProcessor()->setProperty(processors::RunLlamaCppInference::MinP.name,
"invalid_value"));
- property_name = processors::RunLlamaCppInference::MinP.name;
- }
REQUIRE_THROWS(controller.trigger(minifi::test::InputFlowFileData{.content =
"42", .attributes = {}}));
CHECK(minifi::test::utils::verifyLogLinePresenceInPollTime(1s,
diff --git a/extensions/python/ExecutePythonProcessor.cpp
b/extensions/python/ExecutePythonProcessor.cpp
index 184acad78..7ef4ae73a 100644
--- a/extensions/python/ExecutePythonProcessor.cpp
+++ b/extensions/python/ExecutePythonProcessor.cpp
@@ -138,7 +138,8 @@ enum class PropertyValidatorCode : int64_t {
DATA_SIZE = 3,
TIME_PERIOD = 4,
NON_BLANK = 5,
- PORT = 6
+ PORT = 6,
+ NUMBER = 7
};
const core::PropertyValidator& translateCodeToPropertyValidator(const
PropertyValidatorCode& code) {
@@ -156,6 +157,8 @@ const core::PropertyValidator&
translateCodeToPropertyValidator(const PropertyVa
return core::StandardPropertyValidators::NON_BLANK_VALIDATOR;
case PropertyValidatorCode::PORT:
return core::StandardPropertyValidators::PORT_VALIDATOR;
+ case PropertyValidatorCode::NUMBER:
+ return core::StandardPropertyValidators::NUMBER_VALIDATOR;
default:
throw std::invalid_argument("Unknown PropertyValidatorCode");
}
diff --git a/extensions/python/pythonprocessors/nifiapi/properties.py
b/extensions/python/pythonprocessors/nifiapi/properties.py
index 3cbd4c58c..fe0dab092 100644
--- a/extensions/python/pythonprocessors/nifiapi/properties.py
+++ b/extensions/python/pythonprocessors/nifiapi/properties.py
@@ -53,6 +53,9 @@ class ValidatorGenerator:
def createLongValidator(self, *args) -> int:
return StandardValidators.LONG_VALIDATOR
+ def createNumberValidator(self, *args) -> int:
+ return StandardValidators.NUMBER_VALIDATOR
+
class StandardValidators:
_standard_validators = ValidatorGenerator()
@@ -87,6 +90,7 @@ class MinifiPropertyTypes:
TIME_PERIOD_TYPE = 4
NON_BLANK_TYPE = 5
PORT_TYPE = 6
+ NUMBER_TYPE = 7
def translateStandardValidatorToMiNiFiPropertype(validators: List[int]) -> int:
@@ -108,6 +112,8 @@ def
translateStandardValidatorToMiNiFiPropertype(validators: List[int]) -> int:
return MinifiPropertyTypes.NON_BLANK_TYPE
if validator == StandardValidators.PORT_VALIDATOR:
return MinifiPropertyTypes.PORT_TYPE
+ if validator == StandardValidators.NUMBER_VALIDATOR:
+ return MinifiPropertyTypes.NUMBER_TYPE
return None
diff --git a/libminifi/src/minifi-api.cpp b/libminifi/src/minifi-api.cpp
index 8408d6e97..d24cc96d8 100644
--- a/libminifi/src/minifi-api.cpp
+++ b/libminifi/src/minifi-api.cpp
@@ -82,6 +82,7 @@ gsl::not_null<const minifi::core::PropertyValidator*>
toPropertyValidator(minifi
case MINIFI_VALIDATOR_UNSIGNED_INTEGER: return
gsl::make_not_null(&minifi::core::StandardPropertyValidators::UNSIGNED_INTEGER_VALIDATOR);
case MINIFI_VALIDATOR_DATA_SIZE: return
gsl::make_not_null(&minifi::core::StandardPropertyValidators::DATA_SIZE_VALIDATOR);
case MINIFI_VALIDATOR_PORT: return
gsl::make_not_null(&minifi::core::StandardPropertyValidators::PORT_VALIDATOR);
+ case MINIFI_VALIDATOR_NUMBER: return
gsl::make_not_null(&minifi::core::StandardPropertyValidators::NUMBER_VALIDATOR);
}
gsl_FailFast();
}
diff --git a/libminifi/test/unit/PropertyValidationTests.cpp
b/libminifi/test/unit/PropertyValidationTests.cpp
index 62770fa9b..074955191 100644
--- a/libminifi/test/unit/PropertyValidationTests.cpp
+++ b/libminifi/test/unit/PropertyValidationTests.cpp
@@ -224,4 +224,16 @@ TEST_CASE("TimePeriodValue Property") {
CHECK(component.setProperty(property.getName(), "20").error() ==
core::PropertyErrorCode::ValidationFailed);
}
+TEST_CASE("Number validator") {
+ static constexpr auto property_definition =
PropertyDefinitionBuilder<>::createProperty("prop").withValidator(core::StandardPropertyValidators::NUMBER_VALIDATOR).build();
+ const Property property{property_definition};
+ TestConfigurableComponent component;
+ component.setSupportedProperties(std::array<PropertyReference,
1>{property_definition});
+ CHECK(component.setProperty(property.getName(), "20"));
+ CHECK(component.setProperty(property.getName(), "3.14"));
+ CHECK(component.setProperty(property.getName(), "0.0000000001"));
+ CHECK_FALSE(component.setProperty(property.getName(), "10 000"));
+ CHECK_FALSE(component.setProperty(property.getName(), "20 apples"));
+}
+
} // namespace org::apache::nifi::minifi::core
diff --git a/minifi-api/common/include/minifi-cpp/core/PropertyValidator.h
b/minifi-api/common/include/minifi-cpp/core/PropertyValidator.h
index 2d91905ff..06f66e9c2 100644
--- a/minifi-api/common/include/minifi-cpp/core/PropertyValidator.h
+++ b/minifi-api/common/include/minifi-cpp/core/PropertyValidator.h
@@ -25,27 +25,31 @@ namespace org::apache::nifi::minifi::core {
class PropertyValidator {
public:
virtual constexpr ~PropertyValidator() {} // NOLINT can't use = default
because of gcc bug: https://gcc.gnu.org/bugzilla/show_bug.cgi?id=93413
+ PropertyValidator() = default;
+ PropertyValidator(const PropertyValidator&) = delete;
+ PropertyValidator(PropertyValidator&&) = delete;
+ PropertyValidator& operator=(const PropertyValidator& other) = delete;
+ PropertyValidator& operator=(PropertyValidator&& other) = delete;
[[nodiscard]] virtual std::optional<std::string_view>
getEquivalentNifiStandardValidatorName() const = 0;
[[nodiscard]] virtual bool validate(std::string_view input) const = 0;
};
-
class AlwaysValidValidator final : public PropertyValidator {
public:
- AlwaysValidValidator() = default;
- constexpr ~AlwaysValidValidator() override {} // NOLINT see comment at
parent
-
- [[nodiscard]] std::optional<std::string_view>
getEquivalentNifiStandardValidatorName() const override { return "VALID"; }
- [[nodiscard]] bool validate(std::string_view) const override { return true; }
+ [[nodiscard]] std::optional<std::string_view>
getEquivalentNifiStandardValidatorName() const override {
+ return "VALID";
+ }
+ [[nodiscard]] bool validate(std::string_view) const override {
+ return true;
+ }
};
class NonBlankValidator final : public PropertyValidator {
public:
- NonBlankValidator() = default;
- constexpr ~NonBlankValidator() override {} // NOLINT see comment at parent
-
- [[nodiscard]] std::optional<std::string_view>
getEquivalentNifiStandardValidatorName() const override { return
"NON_BLANK_VALIDATOR"; }
+ [[nodiscard]] std::optional<std::string_view>
getEquivalentNifiStandardValidatorName() const override {
+ return "NON_BLANK_VALIDATOR";
+ }
[[nodiscard]] bool validate(const std::string_view input) const override {
return !utils::string::trim(input).empty();
}
@@ -53,10 +57,9 @@ class NonBlankValidator final : public PropertyValidator {
class TimePeriodValidator final : public PropertyValidator {
public:
- TimePeriodValidator() = default;
- constexpr ~TimePeriodValidator() override {} // NOLINT see comment at parent
-
- [[nodiscard]] std::optional<std::string_view>
getEquivalentNifiStandardValidatorName() const override { return
"TIME_PERIOD_VALIDATOR"; }
+ [[nodiscard]] std::optional<std::string_view>
getEquivalentNifiStandardValidatorName() const override {
+ return "TIME_PERIOD_VALIDATOR";
+ }
[[nodiscard]] bool validate(const std::string_view input) const override {
const auto parsed_time =
parsing::parseDuration<std::chrono::nanoseconds>(input);
return parsed_time.has_value();
@@ -65,10 +68,9 @@ class TimePeriodValidator final : public PropertyValidator {
class BooleanValidator final : public PropertyValidator {
public:
- BooleanValidator() = default;
- constexpr ~BooleanValidator() override {} // NOLINT see comment at parent
-
- [[nodiscard]] std::optional<std::string_view>
getEquivalentNifiStandardValidatorName() const override { return
"BOOLEAN_VALIDATOR"; }
+ [[nodiscard]] std::optional<std::string_view>
getEquivalentNifiStandardValidatorName() const override {
+ return "BOOLEAN_VALIDATOR";
+ }
[[nodiscard]] bool validate(const std::string_view input) const override {
const auto parsed_bool = parsing::parseBool(input);
return parsed_bool.has_value();
@@ -77,10 +79,9 @@ class BooleanValidator final : public PropertyValidator {
class IntegerValidator final : public PropertyValidator {
public:
- IntegerValidator() = default;
- constexpr ~IntegerValidator() override {} // NOLINT see comment at parent
-
- [[nodiscard]] std::optional<std::string_view>
getEquivalentNifiStandardValidatorName() const override { return
"INTEGER_VALIDATOR"; }
+ [[nodiscard]] std::optional<std::string_view>
getEquivalentNifiStandardValidatorName() const override {
+ return "INTEGER_VALIDATOR";
+ }
[[nodiscard]] bool validate(const std::string_view input) const override {
const auto parsed_integer = parsing::parseIntegral<int64_t>(input);
return parsed_integer.has_value();
@@ -89,10 +90,9 @@ class IntegerValidator final : public PropertyValidator {
class UnsignedIntegerValidator final : public PropertyValidator {
public:
- UnsignedIntegerValidator() = default;
- constexpr ~UnsignedIntegerValidator() override {} // NOLINT see comment at
parent
-
- [[nodiscard]] std::optional<std::string_view>
getEquivalentNifiStandardValidatorName() const override { return
"NON_NEGATIVE_INTEGER_VALIDATOR"; }
+ [[nodiscard]] std::optional<std::string_view>
getEquivalentNifiStandardValidatorName() const override {
+ return "NON_NEGATIVE_INTEGER_VALIDATOR";
+ }
[[nodiscard]] bool validate(const std::string_view input) const override {
const auto parsed_integer = parsing::parseIntegral<uint64_t>(input);
return parsed_integer.has_value();
@@ -101,10 +101,9 @@ class UnsignedIntegerValidator final : public
PropertyValidator {
class DataSizeValidator final : public PropertyValidator {
public:
- DataSizeValidator() = default;
- constexpr ~DataSizeValidator() override {} // NOLINT see comment at parent
-
- [[nodiscard]] std::optional<std::string_view>
getEquivalentNifiStandardValidatorName() const override { return
"DATA_SIZE_VALIDATOR"; }
+ [[nodiscard]] std::optional<std::string_view>
getEquivalentNifiStandardValidatorName() const override {
+ return "DATA_SIZE_VALIDATOR";
+ }
[[nodiscard]] bool validate(const std::string_view input) const override {
const auto parsed_data_size = parsing::parseDataSize(input);
return parsed_data_size.has_value();
@@ -113,16 +112,26 @@ class DataSizeValidator final : public PropertyValidator {
class PortValidator final : public core::PropertyValidator {
public:
- PortValidator() = default;
- constexpr ~PortValidator() override {} // NOLINT see comment at parent
-
- [[nodiscard]] std::optional<std::string_view>
getEquivalentNifiStandardValidatorName() const override { return
"PORT_VALIDATOR"; }
+ [[nodiscard]] std::optional<std::string_view>
getEquivalentNifiStandardValidatorName() const override {
+ return "PORT_VALIDATOR";
+ }
[[nodiscard]] bool validate(const std::string_view input) const override {
const auto parsed_integer = parsing::parseIntegralMinMax<uint64_t>(input,
0, 65535);
return parsed_integer.has_value();
}
};
+class NumberValidator final : public core::PropertyValidator {
+ public:
+ [[nodiscard]] std::optional<std::string_view>
getEquivalentNifiStandardValidatorName() const override {
+ return "NUMBER_VALIDATOR";
+ }
+ [[nodiscard]] bool validate(const std::string_view input) const override {
+ const auto parsed_number = parsing::parseFloatingPoint<double>(input);
+ return parsed_number.has_value();
+ }
+};
+
namespace StandardPropertyValidators {
inline constexpr auto ALWAYS_VALID_VALIDATOR = AlwaysValidValidator{};
inline constexpr auto NON_BLANK_VALIDATOR = NonBlankValidator{};
@@ -132,6 +141,7 @@ inline constexpr auto INTEGER_VALIDATOR =
IntegerValidator{};
inline constexpr auto UNSIGNED_INTEGER_VALIDATOR = UnsignedIntegerValidator{};
inline constexpr auto DATA_SIZE_VALIDATOR = DataSizeValidator{};
inline constexpr auto PORT_VALIDATOR = PortValidator{};
-}
+inline constexpr auto NUMBER_VALIDATOR = NumberValidator{};
+} // namespace StandardPropertyValidators
} // namespace org::apache::nifi::minifi::core
diff --git a/minifi-api/include/minifi-api.h b/minifi-api/include/minifi-api.h
index 41e748d84..b37f5d8a3 100644
--- a/minifi-api/include/minifi-api.h
+++ b/minifi-api/include/minifi-api.h
@@ -119,6 +119,7 @@ enum minifi_validator : uint32_t {
MINIFI_VALIDATOR_UNSIGNED_INTEGER = 5,
MINIFI_VALIDATOR_DATA_SIZE = 6,
MINIFI_VALIDATOR_PORT = 7,
+ MINIFI_VALIDATOR_NUMBER = 8,
};
struct minifi_property_definition {