simplibs-validate 0.1.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- simplibs_validate-0.1.0/LICENSE +21 -0
- simplibs_validate-0.1.0/PKG-INFO +659 -0
- simplibs_validate-0.1.0/README.md +630 -0
- simplibs_validate-0.1.0/pyproject.toml +63 -0
- simplibs_validate-0.1.0/setup.cfg +4 -0
- simplibs_validate-0.1.0/src/simplibs/validate/__init__.py +46 -0
- simplibs_validate-0.1.0/src/simplibs/validate/exceptions/ParamError.py +31 -0
- simplibs_validate-0.1.0/src/simplibs/validate/exceptions/ValidateError.py +44 -0
- simplibs_validate-0.1.0/src/simplibs/validate/exceptions/ValidationError.py +30 -0
- simplibs_validate-0.1.0/src/simplibs/validate/exceptions/__init__.py +31 -0
- simplibs_validate-0.1.0/src/simplibs/validate/exceptions/build_validation_error.py +52 -0
- simplibs_validate-0.1.0/src/simplibs/validate/raise_invalid.py +84 -0
- simplibs_validate-0.1.0/src/simplibs/validate/rules/__init__.py +855 -0
- simplibs_validate-0.1.0/src/simplibs/validate/rules/base_class/Rule.py +280 -0
- simplibs_validate-0.1.0/src/simplibs/validate/rules/base_class/__init__.py +17 -0
- simplibs_validate-0.1.0/src/simplibs/validate/rules/containers/AllOf.py +147 -0
- simplibs_validate-0.1.0/src/simplibs/validate/rules/containers/AnyOf.py +146 -0
- simplibs_validate-0.1.0/src/simplibs/validate/rules/containers/Compose.py +148 -0
- simplibs_validate-0.1.0/src/simplibs/validate/rules/containers/ForEach.py +120 -0
- simplibs_validate-0.1.0/src/simplibs/validate/rules/containers/NoneOf.py +112 -0
- simplibs_validate-0.1.0/src/simplibs/validate/rules/containers/Not.py +97 -0
- simplibs_validate-0.1.0/src/simplibs/validate/rules/containers/__init__.py +28 -0
- simplibs_validate-0.1.0/src/simplibs/validate/rules/containers/_helpers/__init__.py +22 -0
- simplibs_validate-0.1.0/src/simplibs/validate/rules/containers/_helpers/as_predicate.py +78 -0
- simplibs_validate-0.1.0/src/simplibs/validate/rules/containers/_helpers/build_child_exception.py +39 -0
- simplibs_validate-0.1.0/src/simplibs/validate/rules/containers/_helpers/describe_rule.py +72 -0
- simplibs_validate-0.1.0/src/simplibs/validate/rules/containers/_init_validators/__init__.py +23 -0
- simplibs_validate-0.1.0/src/simplibs/validate/rules/containers/_init_validators/raise_container_param_not_type_error.py +53 -0
- simplibs_validate-0.1.0/src/simplibs/validate/rules/containers/_init_validators/raise_requires_at_least_one_rule_error.py +38 -0
- simplibs_validate-0.1.0/src/simplibs/validate/rules/containers/_init_validators/raise_rule_param_not_callable.py +55 -0
- simplibs_validate-0.1.0/src/simplibs/validate/rules/containers/_init_validators/validate_compose_param_is_callable.py +73 -0
- simplibs_validate-0.1.0/src/simplibs/validate/rules/predicates/__init__.py +87 -0
- simplibs_validate-0.1.0/src/simplibs/validate/rules/predicates/_helpers/__init__.py +18 -0
- simplibs_validate-0.1.0/src/simplibs/validate/rules/predicates/_helpers/accepts_one_positional_argument.py +127 -0
- simplibs_validate-0.1.0/src/simplibs/validate/rules/predicates/_helpers/format_container.py +50 -0
- simplibs_validate-0.1.0/src/simplibs/validate/rules/predicates/_init_validators/__init__.py +40 -0
- simplibs_validate-0.1.0/src/simplibs/validate/rules/predicates/_init_validators/rule_errors/__init__.py +21 -0
- simplibs_validate-0.1.0/src/simplibs/validate/rules/predicates/_init_validators/rule_errors/raise_has_length_param_conflict_error.py +54 -0
- simplibs_validate-0.1.0/src/simplibs/validate/rules/predicates/_init_validators/rule_errors/raise_regex_param_invalid_pattern_error.py +44 -0
- simplibs_validate-0.1.0/src/simplibs/validate/rules/predicates/_init_validators/rule_errors/raise_user_rule_param_wrong_arity.py +54 -0
- simplibs_validate-0.1.0/src/simplibs/validate/rules/predicates/_init_validators/shared_errors/__init__.py +32 -0
- simplibs_validate-0.1.0/src/simplibs/validate/rules/predicates/_init_validators/shared_errors/raise_param_min_max_bounds_inverted_error.py +79 -0
- simplibs_validate-0.1.0/src/simplibs/validate/rules/predicates/_init_validators/shared_errors/raise_param_min_max_incomparable_error.py +66 -0
- simplibs_validate-0.1.0/src/simplibs/validate/rules/predicates/_init_validators/shared_errors/raise_param_missing_error.py +78 -0
- simplibs_validate-0.1.0/src/simplibs/validate/rules/predicates/_init_validators/shared_errors/raise_param_not_callable_error.py +52 -0
- simplibs_validate-0.1.0/src/simplibs/validate/rules/predicates/_init_validators/shared_errors/raise_param_not_container_error.py +76 -0
- simplibs_validate-0.1.0/src/simplibs/validate/rules/predicates/_init_validators/shared_errors/raise_param_not_non_negative_integer_error.py +89 -0
- simplibs_validate-0.1.0/src/simplibs/validate/rules/predicates/_init_validators/shared_errors/raise_param_not_string_error.py +78 -0
- simplibs_validate-0.1.0/src/simplibs/validate/rules/predicates/_init_validators/shared_errors/raise_param_not_type_error.py +66 -0
- simplibs_validate-0.1.0/src/simplibs/validate/rules/predicates/_init_validators/shared_validators/__init__.py +24 -0
- simplibs_validate-0.1.0/src/simplibs/validate/rules/predicates/_init_validators/shared_validators/validate_param_is_integer.py +74 -0
- simplibs_validate-0.1.0/src/simplibs/validate/rules/predicates/_init_validators/shared_validators/validate_param_is_not_zero.py +70 -0
- simplibs_validate-0.1.0/src/simplibs/validate/rules/predicates/_init_validators/shared_validators/validate_param_is_primitive_number.py +77 -0
- simplibs_validate-0.1.0/src/simplibs/validate/rules/predicates/_init_validators/shared_validators/validate_param_remainder_in_range.py +59 -0
- simplibs_validate-0.1.0/src/simplibs/validate/rules/predicates/arithmetic/CloseTo.py +149 -0
- simplibs_validate-0.1.0/src/simplibs/validate/rules/predicates/arithmetic/DivisibleBy.py +120 -0
- simplibs_validate-0.1.0/src/simplibs/validate/rules/predicates/arithmetic/HasRemainder.py +137 -0
- simplibs_validate-0.1.0/src/simplibs/validate/rules/predicates/arithmetic/__init__.py +21 -0
- simplibs_validate-0.1.0/src/simplibs/validate/rules/predicates/checkers/IsEmpty.py +101 -0
- simplibs_validate-0.1.0/src/simplibs/validate/rules/predicates/checkers/IsFalse.py +81 -0
- simplibs_validate-0.1.0/src/simplibs/validate/rules/predicates/checkers/IsNone.py +81 -0
- simplibs_validate-0.1.0/src/simplibs/validate/rules/predicates/checkers/IsTrue.py +80 -0
- simplibs_validate-0.1.0/src/simplibs/validate/rules/predicates/checkers/NotEmpty.py +100 -0
- simplibs_validate-0.1.0/src/simplibs/validate/rules/predicates/checkers/__init__.py +25 -0
- simplibs_validate-0.1.0/src/simplibs/validate/rules/predicates/collections/AllUnique.py +124 -0
- simplibs_validate-0.1.0/src/simplibs/validate/rules/predicates/collections/HasItem.py +132 -0
- simplibs_validate-0.1.0/src/simplibs/validate/rules/predicates/collections/HasKey.py +104 -0
- simplibs_validate-0.1.0/src/simplibs/validate/rules/predicates/collections/HasKeys.py +115 -0
- simplibs_validate-0.1.0/src/simplibs/validate/rules/predicates/collections/IsContainer.py +99 -0
- simplibs_validate-0.1.0/src/simplibs/validate/rules/predicates/collections/IsSubsetOf.py +139 -0
- simplibs_validate-0.1.0/src/simplibs/validate/rules/predicates/collections/IsSupersetOf.py +138 -0
- simplibs_validate-0.1.0/src/simplibs/validate/rules/predicates/collections/__init__.py +29 -0
- simplibs_validate-0.1.0/src/simplibs/validate/rules/predicates/comparisons/Equals.py +87 -0
- simplibs_validate-0.1.0/src/simplibs/validate/rules/predicates/comparisons/GreaterOrEqual.py +106 -0
- simplibs_validate-0.1.0/src/simplibs/validate/rules/predicates/comparisons/GreaterThan.py +106 -0
- simplibs_validate-0.1.0/src/simplibs/validate/rules/predicates/comparisons/InRange.py +166 -0
- simplibs_validate-0.1.0/src/simplibs/validate/rules/predicates/comparisons/LessOrEqual.py +106 -0
- simplibs_validate-0.1.0/src/simplibs/validate/rules/predicates/comparisons/LessThan.py +106 -0
- simplibs_validate-0.1.0/src/simplibs/validate/rules/predicates/comparisons/NotEquals.py +88 -0
- simplibs_validate-0.1.0/src/simplibs/validate/rules/predicates/comparisons/__init__.py +29 -0
- simplibs_validate-0.1.0/src/simplibs/validate/rules/predicates/introspection/HasAttribute.py +95 -0
- simplibs_validate-0.1.0/src/simplibs/validate/rules/predicates/introspection/HasLength.py +177 -0
- simplibs_validate-0.1.0/src/simplibs/validate/rules/predicates/introspection/IsCallable.py +81 -0
- simplibs_validate-0.1.0/src/simplibs/validate/rules/predicates/introspection/IsDataclass.py +84 -0
- simplibs_validate-0.1.0/src/simplibs/validate/rules/predicates/introspection/IsHashable.py +91 -0
- simplibs_validate-0.1.0/src/simplibs/validate/rules/predicates/introspection/IsInstance.py +105 -0
- simplibs_validate-0.1.0/src/simplibs/validate/rules/predicates/introspection/IsIterable.py +90 -0
- simplibs_validate-0.1.0/src/simplibs/validate/rules/predicates/introspection/IsSubclass.py +122 -0
- simplibs_validate-0.1.0/src/simplibs/validate/rules/predicates/introspection/IsType.py +82 -0
- simplibs_validate-0.1.0/src/simplibs/validate/rules/predicates/introspection/__init__.py +34 -0
- simplibs_validate-0.1.0/src/simplibs/validate/rules/predicates/logic/Is.py +88 -0
- simplibs_validate-0.1.0/src/simplibs/validate/rules/predicates/logic/IsIn.py +145 -0
- simplibs_validate-0.1.0/src/simplibs/validate/rules/predicates/logic/IsNot.py +89 -0
- simplibs_validate-0.1.0/src/simplibs/validate/rules/predicates/logic/NotIn.py +145 -0
- simplibs_validate-0.1.0/src/simplibs/validate/rules/predicates/logic/UserRule.py +118 -0
- simplibs_validate-0.1.0/src/simplibs/validate/rules/predicates/logic/__init__.py +24 -0
- simplibs_validate-0.1.0/src/simplibs/validate/rules/predicates/numeric/IsBool.py +96 -0
- simplibs_validate-0.1.0/src/simplibs/validate/rules/predicates/numeric/IsDecimal.py +83 -0
- simplibs_validate-0.1.0/src/simplibs/validate/rules/predicates/numeric/IsFloat.py +75 -0
- simplibs_validate-0.1.0/src/simplibs/validate/rules/predicates/numeric/IsInfinity.py +97 -0
- simplibs_validate-0.1.0/src/simplibs/validate/rules/predicates/numeric/IsInteger.py +118 -0
- simplibs_validate-0.1.0/src/simplibs/validate/rules/predicates/numeric/IsNan.py +98 -0
- simplibs_validate-0.1.0/src/simplibs/validate/rules/predicates/numeric/IsNumber.py +96 -0
- simplibs_validate-0.1.0/src/simplibs/validate/rules/predicates/numeric/IsPi.py +138 -0
- simplibs_validate-0.1.0/src/simplibs/validate/rules/predicates/numeric/IsPrimitiveNumber.py +87 -0
- simplibs_validate-0.1.0/src/simplibs/validate/rules/predicates/numeric/IsZero.py +109 -0
- simplibs_validate-0.1.0/src/simplibs/validate/rules/predicates/numeric/__init__.py +36 -0
- simplibs_validate-0.1.0/src/simplibs/validate/rules/predicates/strings/Contains.py +114 -0
- simplibs_validate-0.1.0/src/simplibs/validate/rules/predicates/strings/EndsWith.py +114 -0
- simplibs_validate-0.1.0/src/simplibs/validate/rules/predicates/strings/IsBlank.py +98 -0
- simplibs_validate-0.1.0/src/simplibs/validate/rules/predicates/strings/IsString.py +104 -0
- simplibs_validate-0.1.0/src/simplibs/validate/rules/predicates/strings/IsSubstringOf.py +114 -0
- simplibs_validate-0.1.0/src/simplibs/validate/rules/predicates/strings/NotBlank.py +98 -0
- simplibs_validate-0.1.0/src/simplibs/validate/rules/predicates/strings/Regex.py +126 -0
- simplibs_validate-0.1.0/src/simplibs/validate/rules/predicates/strings/StartsWith.py +114 -0
- simplibs_validate-0.1.0/src/simplibs/validate/rules/predicates/strings/__init__.py +30 -0
- simplibs_validate-0.1.0/src/simplibs/validate/rules/typing/IsAny.py +114 -0
- simplibs_validate-0.1.0/src/simplibs/validate/rules/typing/IsTyping.py +100 -0
- simplibs_validate-0.1.0/src/simplibs/validate/rules/typing/__init__.py +26 -0
- simplibs_validate-0.1.0/src/simplibs/validate/rules/typing/_builders/ORIGIN_TABLE.py +112 -0
- simplibs_validate-0.1.0/src/simplibs/validate/rules/typing/_builders/__init__.py +35 -0
- simplibs_validate-0.1.0/src/simplibs/validate/rules/typing/_builders/build_annotated_rule.py +106 -0
- simplibs_validate-0.1.0/src/simplibs/validate/rules/typing/_builders/build_any_of_rule.py +73 -0
- simplibs_validate-0.1.0/src/simplibs/validate/rules/typing/_builders/build_callable_rule.py +63 -0
- simplibs_validate-0.1.0/src/simplibs/validate/rules/typing/_builders/build_elements_rule.py +109 -0
- simplibs_validate-0.1.0/src/simplibs/validate/rules/typing/_builders/build_key_value_rule.py +65 -0
- simplibs_validate-0.1.0/src/simplibs/validate/rules/typing/_builders/build_literal_rule.py +60 -0
- simplibs_validate-0.1.0/src/simplibs/validate/rules/typing/_builders/build_tuple_rule.py +111 -0
- simplibs_validate-0.1.0/src/simplibs/validate/rules/typing/_builders/build_type_rule.py +114 -0
- simplibs_validate-0.1.0/src/simplibs/validate/rules/typing/_validations/__init__.py +16 -0
- simplibs_validate-0.1.0/src/simplibs/validate/rules/typing/_validations/raise_unsupported_annotation_error.py +64 -0
- simplibs_validate-0.1.0/src/simplibs/validate/rules/typing/build_typing_rule.py +131 -0
- simplibs_validate-0.1.0/src/simplibs/validate/rules/typing/tools/__init__.py +20 -0
- simplibs_validate-0.1.0/src/simplibs/validate/rules/typing/tools/get_supported_origins.py +42 -0
- simplibs_validate-0.1.0/src/simplibs/validate/rules/typing/tools/is_supported_annotation.py +60 -0
- simplibs_validate-0.1.0/src/simplibs/validate/testing/__init__.py +43 -0
- simplibs_validate-0.1.0/src/simplibs/validate/testing/assert_rule_contract.py +198 -0
- simplibs_validate-0.1.0/src/simplibs/validate/testing/assert_validate_wrapper.py +81 -0
- simplibs_validate-0.1.0/src/simplibs/validate/testing/asserts/__init__.py +27 -0
- simplibs_validate-0.1.0/src/simplibs/validate/testing/asserts/assert_rule_build_exception.py +149 -0
- simplibs_validate-0.1.0/src/simplibs/validate/testing/asserts/assert_rule_is_valid.py +90 -0
- simplibs_validate-0.1.0/src/simplibs/validate/testing/asserts/assert_rule_param_error.py +78 -0
- simplibs_validate-0.1.0/src/simplibs/validate/testing/asserts/assert_rule_raise_invalid.py +91 -0
- simplibs_validate-0.1.0/src/simplibs/validate/testing/asserts/assert_rule_validate.py +107 -0
- simplibs_validate-0.1.0/src/simplibs/validate/tools/__init__.py +33 -0
- simplibs_validate-0.1.0/src/simplibs/validate/tools/log_this/__init__.py +16 -0
- simplibs_validate-0.1.0/src/simplibs/validate/tools/log_this/_helpers/__init__.py +24 -0
- simplibs_validate-0.1.0/src/simplibs/validate/tools/log_this/_helpers/format_bound_arguments.py +65 -0
- simplibs_validate-0.1.0/src/simplibs/validate/tools/log_this/_helpers/get_context_info.py +34 -0
- simplibs_validate-0.1.0/src/simplibs/validate/tools/log_this/_helpers/log_exception.py +68 -0
- simplibs_validate-0.1.0/src/simplibs/validate/tools/log_this/_helpers/log_start.py +40 -0
- simplibs_validate-0.1.0/src/simplibs/validate/tools/log_this/_helpers/log_success.py +74 -0
- simplibs_validate-0.1.0/src/simplibs/validate/tools/log_this/log_this.py +232 -0
- simplibs_validate-0.1.0/src/simplibs/validate/tools/override_rules/__init__.py +15 -0
- simplibs_validate-0.1.0/src/simplibs/validate/tools/override_rules/_validations/__init__.py +14 -0
- simplibs_validate-0.1.0/src/simplibs/validate/tools/override_rules/_validations/raise_override_rules_invalid_error.py +51 -0
- simplibs_validate-0.1.0/src/simplibs/validate/tools/override_rules/override_rules.py +97 -0
- simplibs_validate-0.1.0/src/simplibs/validate/tools/validate_call/__init__.py +16 -0
- simplibs_validate-0.1.0/src/simplibs/validate/tools/validate_call/_helpers/__init__.py +24 -0
- simplibs_validate-0.1.0/src/simplibs/validate/tools/validate_call/_helpers/compile_parameter_rules.py +133 -0
- simplibs_validate-0.1.0/src/simplibs/validate/tools/validate_call/_helpers/compile_return_rule.py +75 -0
- simplibs_validate-0.1.0/src/simplibs/validate/tools/validate_call/_helpers/get_context_string.py +29 -0
- simplibs_validate-0.1.0/src/simplibs/validate/tools/validate_call/_helpers/is_bypass_parameter.py +68 -0
- simplibs_validate-0.1.0/src/simplibs/validate/tools/validate_call/_helpers/should_validate.py +68 -0
- simplibs_validate-0.1.0/src/simplibs/validate/tools/validate_call/_validations/__init__.py +19 -0
- simplibs_validate-0.1.0/src/simplibs/validate/tools/validate_call/_validations/raise_no_rule_for_checked_param.py +47 -0
- simplibs_validate-0.1.0/src/simplibs/validate/tools/validate_call/_validations/raise_no_rule_for_return.py +43 -0
- simplibs_validate-0.1.0/src/simplibs/validate/tools/validate_call/validate_call.py +335 -0
- simplibs_validate-0.1.0/src/simplibs/validate/tools/validate_dataclass/__init__.py +16 -0
- simplibs_validate-0.1.0/src/simplibs/validate/tools/validate_dataclass/_helpers/__init__.py +16 -0
- simplibs_validate-0.1.0/src/simplibs/validate/tools/validate_dataclass/_helpers/get_dataclass_context_string.py +30 -0
- simplibs_validate-0.1.0/src/simplibs/validate/tools/validate_dataclass/_validations/__init__.py +16 -0
- simplibs_validate-0.1.0/src/simplibs/validate/tools/validate_dataclass/_validations/raise_not_a_dataclass_error.py +44 -0
- simplibs_validate-0.1.0/src/simplibs/validate/tools/validate_dataclass/validate_dataclass.py +206 -0
- simplibs_validate-0.1.0/src/simplibs/validate/tools/validated_type/__init__.py +15 -0
- simplibs_validate-0.1.0/src/simplibs/validate/tools/validated_type/_validations/__init__.py +17 -0
- simplibs_validate-0.1.0/src/simplibs/validate/tools/validated_type/_validations/raise_validated_type_missing_rule_error.py +46 -0
- simplibs_validate-0.1.0/src/simplibs/validate/tools/validated_type/_validations/raise_validated_type_rule_invalid_error.py +47 -0
- simplibs_validate-0.1.0/src/simplibs/validate/tools/validated_type/validated_type.py +147 -0
- simplibs_validate-0.1.0/src/simplibs/validate/validate.py +145 -0
- simplibs_validate-0.1.0/src/simplibs/validate/validators/__init__.py +67 -0
- simplibs_validate-0.1.0/src/simplibs/validate/validators/rules/__init__.py +30 -0
- simplibs_validate-0.1.0/src/simplibs/validate/validators/rules/boolean_rule.py +88 -0
- simplibs_validate-0.1.0/src/simplibs/validate/validators/rules/container_rule.py +141 -0
- simplibs_validate-0.1.0/src/simplibs/validate/validators/rules/float_rule.py +172 -0
- simplibs_validate-0.1.0/src/simplibs/validate/validators/rules/integer_rule.py +161 -0
- simplibs_validate-0.1.0/src/simplibs/validate/validators/rules/mapping_rule.py +123 -0
- simplibs_validate-0.1.0/src/simplibs/validate/validators/rules/number_rule.py +136 -0
- simplibs_validate-0.1.0/src/simplibs/validate/validators/rules/string_rule.py +193 -0
- simplibs_validate-0.1.0/src/simplibs/validate/validators/rules/type_rule.py +104 -0
- simplibs_validate-0.1.0/src/simplibs/validate/validators/validate_bool.py +59 -0
- simplibs_validate-0.1.0/src/simplibs/validate/validators/validate_container.py +87 -0
- simplibs_validate-0.1.0/src/simplibs/validate/validators/validate_float.py +102 -0
- simplibs_validate-0.1.0/src/simplibs/validate/validators/validate_int.py +96 -0
- simplibs_validate-0.1.0/src/simplibs/validate/validators/validate_mapping.py +75 -0
- simplibs_validate-0.1.0/src/simplibs/validate/validators/validate_number.py +89 -0
- simplibs_validate-0.1.0/src/simplibs/validate/validators/validate_str.py +123 -0
- simplibs_validate-0.1.0/src/simplibs/validate/validators/validate_type.py +73 -0
- simplibs_validate-0.1.0/src/simplibs_validate.egg-info/PKG-INFO +659 -0
- simplibs_validate-0.1.0/src/simplibs_validate.egg-info/SOURCES.txt +203 -0
- simplibs_validate-0.1.0/src/simplibs_validate.egg-info/dependency_links.txt +1 -0
- simplibs_validate-0.1.0/src/simplibs_validate.egg-info/requires.txt +6 -0
- simplibs_validate-0.1.0/src/simplibs_validate.egg-info/top_level.txt +1 -0
- simplibs_validate-0.1.0/tests/test_raise_invalid.py +55 -0
- simplibs_validate-0.1.0/tests/test_validate.py +109 -0
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Dalibor Sova (Sudip2708)
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in
|
|
13
|
+
all copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
|
21
|
+
THE SOFTWARE.
|
|
@@ -0,0 +1,659 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: simplibs-validate
|
|
3
|
+
Version: 0.1.0
|
|
4
|
+
Summary: A powerful, composable, and developer-friendly validation framework for Python with detailed diagnostic telemetry.
|
|
5
|
+
Author-email: "Dalibor Sova (Sudip2708)" <daliborsova@seznam.cz>
|
|
6
|
+
License-Expression: MIT
|
|
7
|
+
Project-URL: Homepage, https://github.com/simplibs/simplibs-validate
|
|
8
|
+
Project-URL: Repository, https://github.com/simplibs/simplibs-validate
|
|
9
|
+
Project-URL: Issues, https://github.com/simplibs/simplibs-validate/issues
|
|
10
|
+
Project-URL: Changelog, https://github.com/simplibs/simplibs-validate/blob/main/CHANGELOG.md
|
|
11
|
+
Keywords: validation,validator,schema,rules,data-validation,type-hints,testing,simplibs,simplibs-validate,developer-tools
|
|
12
|
+
Classifier: Development Status :: 3 - Alpha
|
|
13
|
+
Classifier: Intended Audience :: Developers
|
|
14
|
+
Classifier: Programming Language :: Python :: 3
|
|
15
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
16
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
17
|
+
Classifier: Programming Language :: Python :: 3.13
|
|
18
|
+
Classifier: Topic :: Software Development :: Libraries :: Python Modules
|
|
19
|
+
Classifier: Topic :: Software Development :: Testing
|
|
20
|
+
Requires-Python: >=3.11
|
|
21
|
+
Description-Content-Type: text/markdown
|
|
22
|
+
License-File: LICENSE
|
|
23
|
+
Requires-Dist: simplibs-exception>=1.0.0
|
|
24
|
+
Requires-Dist: simplibs-sentinels>=0.1.0
|
|
25
|
+
Provides-Extra: dev
|
|
26
|
+
Requires-Dist: pytest>=7.0; extra == "dev"
|
|
27
|
+
Requires-Dist: pytest-asyncio>=0.21.0; extra == "dev"
|
|
28
|
+
Dynamic: license-file
|
|
29
|
+
|
|
30
|
+
# ⚖️ `simplibs-validate`
|
|
31
|
+
|
|
32
|
+
[](https://pypi.org/project/simplibs-validate/)
|
|
33
|
+
[](https://www.python.org/downloads/)
|
|
34
|
+
[](https://github.com/simplibs/simplibs-validate/blob/main/LICENSE)
|
|
35
|
+
|
|
36
|
+
**Composable, explicit validation — no magic, no data transformation, just answers.**
|
|
37
|
+
|
|
38
|
+
A lightweight Python library for validating values against rules built from small,
|
|
39
|
+
single-purpose predicate classes. Rules compose with plain operators (`|`, `&`, `~`),
|
|
40
|
+
carry structured, human-readable diagnostics on failure, and — through `IsTyping` —
|
|
41
|
+
understand your existing type annotations directly, so a whole function's inputs can
|
|
42
|
+
be validated automatically from its own signature.
|
|
43
|
+
|
|
44
|
+
```python
|
|
45
|
+
from simplibs.validate import validate, is_integer, greater_than
|
|
46
|
+
|
|
47
|
+
validate(5, is_integer & greater_than(0)) # -> True
|
|
48
|
+
validate(-5, is_integer & greater_than(0)) # -> raises ValidationError
|
|
49
|
+
```
|
|
50
|
+
|
|
51
|
+
---
|
|
52
|
+
|
|
53
|
+
## 🧭 The Core Philosophy
|
|
54
|
+
|
|
55
|
+
Most validation approaches force a choice: either write ad-hoc `if`/`raise` checks
|
|
56
|
+
scattered through your codebase, or adopt a heavy framework that also wants to parse,
|
|
57
|
+
coerce, and serialize your data along the way. `simplibs-validate` is neither — it's a
|
|
58
|
+
**pure predicate engine**. A `Rule` never transforms a value; it only ever answers "does
|
|
59
|
+
this satisfy me?" and, on failure, explains exactly why.
|
|
60
|
+
|
|
61
|
+
Every rule is a small, composable object. Combine them with plain Python operators
|
|
62
|
+
instead of nested configuration:
|
|
63
|
+
|
|
64
|
+
```python
|
|
65
|
+
is_string & has_length(min_length=3) & not_blank
|
|
66
|
+
```
|
|
67
|
+
|
|
68
|
+
And because rules already understand Python's own typing system, the same machinery
|
|
69
|
+
that powers `validate()` also powers `@validate_call` — a decorator that validates an
|
|
70
|
+
entire function's arguments straight from its type hints, no separate schema to
|
|
71
|
+
maintain:
|
|
72
|
+
|
|
73
|
+
```python
|
|
74
|
+
from simplibs.validate import validate_call, validated_type
|
|
75
|
+
|
|
76
|
+
PositiveInt = validated_type(int, greater_than(0))
|
|
77
|
+
|
|
78
|
+
@validate_call
|
|
79
|
+
def register(age: PositiveInt, *, validate: bool = True) -> None:
|
|
80
|
+
...
|
|
81
|
+
|
|
82
|
+
register(25) # validated normally
|
|
83
|
+
register(-5) # raises ValidationError
|
|
84
|
+
register(-5, validate=False) # explicitly skipped — e.g. already validated upstream
|
|
85
|
+
```
|
|
86
|
+
|
|
87
|
+
That combination — annotation-driven rules, a decorator that enforces them
|
|
88
|
+
automatically, and a per-call opt-out for code paths that already trust their data —
|
|
89
|
+
is what lets you build fully self-validating functions and dataclasses from nothing
|
|
90
|
+
more than their own signatures.
|
|
91
|
+
|
|
92
|
+
---
|
|
93
|
+
|
|
94
|
+
## 📦 Installation
|
|
95
|
+
|
|
96
|
+
```bash
|
|
97
|
+
pip install simplibs-validate
|
|
98
|
+
```
|
|
99
|
+
|
|
100
|
+
---
|
|
101
|
+
|
|
102
|
+
## 🚀 Quick Start in 60 Seconds
|
|
103
|
+
|
|
104
|
+
### Level 1: One-off validation
|
|
105
|
+
|
|
106
|
+
```python
|
|
107
|
+
from simplibs.validate import validate, is_integer, greater_than
|
|
108
|
+
|
|
109
|
+
validate(5, is_integer & greater_than(0))
|
|
110
|
+
validate(5, is_integer & greater_than(0), return_bool=True) # -> True, no exception
|
|
111
|
+
validate("x", is_integer, return_bool=True) # -> False, no exception
|
|
112
|
+
```
|
|
113
|
+
|
|
114
|
+
### Level 2: Ready-made validators
|
|
115
|
+
|
|
116
|
+
Every common type has a batteries-included `validate_*` function, taking the
|
|
117
|
+
constraint as plain keyword arguments — no rule composition required:
|
|
118
|
+
|
|
119
|
+
```python
|
|
120
|
+
from simplibs.validate import validate_string, validate_int
|
|
121
|
+
|
|
122
|
+
validate_string("user@example.com", contains="@", min_length=5)
|
|
123
|
+
validate_int(42, greater_than=0, divisible_by=2)
|
|
124
|
+
```
|
|
125
|
+
|
|
126
|
+
### Level 3: Annotation-driven, self-validating functions
|
|
127
|
+
|
|
128
|
+
```python
|
|
129
|
+
from simplibs.validate import validate_call
|
|
130
|
+
|
|
131
|
+
@validate_call
|
|
132
|
+
def create_user(name: str, age: int) -> dict:
|
|
133
|
+
return {"name": name, "age": age}
|
|
134
|
+
|
|
135
|
+
create_user("Alice", 30) # validated automatically from the annotations
|
|
136
|
+
create_user("Alice", "30") # raises ValidationError
|
|
137
|
+
```
|
|
138
|
+
|
|
139
|
+
---
|
|
140
|
+
|
|
141
|
+
## 🛠️ The Architecture: 3 Layers
|
|
142
|
+
|
|
143
|
+
```
|
|
144
|
+
┌─────────────────────────┐
|
|
145
|
+
│ Rules │ ◄── Rule subclasses + snake_case shortcuts
|
|
146
|
+
└────────────┬────────────┘
|
|
147
|
+
▼
|
|
148
|
+
┌─────────────────────────┐
|
|
149
|
+
│ Validators │ ◄── validate_string, validate_int, ... presets
|
|
150
|
+
└────────────┬────────────┘
|
|
151
|
+
▼
|
|
152
|
+
┌─────────────────────────┐
|
|
153
|
+
│ Tools │ ◄── validate_call, validate_dataclass, log_this, ...
|
|
154
|
+
└─────────────────────────┘
|
|
155
|
+
```
|
|
156
|
+
|
|
157
|
+
### 1. `validate` — the universal entry point
|
|
158
|
+
|
|
159
|
+
Every validation ultimately goes through one of two functions:
|
|
160
|
+
|
|
161
|
+
* **`validate(value, rule, ...)`** — evaluates `rule` against `value`, then either
|
|
162
|
+
returns (`True`/the value) or raises, depending on the flags given. Use this
|
|
163
|
+
everywhere you actually need the check performed.
|
|
164
|
+
* **`raise_invalid(value, rule, ...)`** — unconditionally builds and raises the
|
|
165
|
+
diagnostic exception for `rule`, without evaluating anything. Use this where your
|
|
166
|
+
own code has *already* determined a value is invalid (e.g. inside an `if not
|
|
167
|
+
condition:` branch) and you just want the same structured `ValidateError` card
|
|
168
|
+
`validate()` would have produced, without redundantly re-running the check.
|
|
169
|
+
|
|
170
|
+
```python
|
|
171
|
+
def validate(
|
|
172
|
+
value: Any,
|
|
173
|
+
rule: Rule | Callable[[Any], bool],
|
|
174
|
+
*,
|
|
175
|
+
value_name: str | None = None,
|
|
176
|
+
context: str | None = None,
|
|
177
|
+
return_bool: bool = False,
|
|
178
|
+
return_value: bool = False,
|
|
179
|
+
) -> Any:
|
|
180
|
+
|
|
181
|
+
# 1. Rule instance handling — delegate entirely to Rule.validate()
|
|
182
|
+
if isinstance(rule, Rule):
|
|
183
|
+
return rule.validate(
|
|
184
|
+
value,
|
|
185
|
+
value_name=value_name,
|
|
186
|
+
context=context,
|
|
187
|
+
return_bool=return_bool,
|
|
188
|
+
return_value=return_value,
|
|
189
|
+
)
|
|
190
|
+
|
|
191
|
+
# 2. Callable handling (plain function / lambda)
|
|
192
|
+
# 2.1 Validation execution and success handling
|
|
193
|
+
if rule(value):
|
|
194
|
+
return value if return_value else True
|
|
195
|
+
|
|
196
|
+
# 2.2 Return bool handling
|
|
197
|
+
if return_bool:
|
|
198
|
+
return False
|
|
199
|
+
|
|
200
|
+
# 2.3 Failure handling
|
|
201
|
+
raise build_validation_error(
|
|
202
|
+
rule,
|
|
203
|
+
value,
|
|
204
|
+
value_name=value_name,
|
|
205
|
+
context=context,
|
|
206
|
+
)
|
|
207
|
+
|
|
208
|
+
```
|
|
209
|
+
|
|
210
|
+
```python
|
|
211
|
+
def raise_invalid(
|
|
212
|
+
value: Any,
|
|
213
|
+
rule: Rule | Callable[[Any], bool],
|
|
214
|
+
*,
|
|
215
|
+
value_name: str | None = None,
|
|
216
|
+
context: str | None = None,
|
|
217
|
+
) -> NoReturn:
|
|
218
|
+
|
|
219
|
+
# 1. Rule instance handling
|
|
220
|
+
if isinstance(rule, Rule):
|
|
221
|
+
raise rule.build_exception(
|
|
222
|
+
value,
|
|
223
|
+
value_name=value_name,
|
|
224
|
+
context=context,
|
|
225
|
+
)
|
|
226
|
+
|
|
227
|
+
# 2. Callable handling (plain function / lambda)
|
|
228
|
+
raise build_validation_error(
|
|
229
|
+
rule,
|
|
230
|
+
value,
|
|
231
|
+
value_name=value_name,
|
|
232
|
+
context=context,
|
|
233
|
+
)
|
|
234
|
+
```
|
|
235
|
+
|
|
236
|
+
Both accept either a `Rule` instance or a plain callable predicate — a `Rule` delegates
|
|
237
|
+
to its own `validate()`/`build_exception()`, while a callable is evaluated directly and,
|
|
238
|
+
on failure, wrapped in a generic diagnostic via `build_validation_error`.
|
|
239
|
+
|
|
240
|
+
### 2. Specialized validators
|
|
241
|
+
|
|
242
|
+
For the most common types, a ready-made `validate_*` function exposes every relevant
|
|
243
|
+
constraint as a plain keyword argument, composing the equivalent `Rule` tree
|
|
244
|
+
internally — no manual `&`-chaining required for everyday cases.
|
|
245
|
+
|
|
246
|
+
| Validator | Description | Docs |
|
|
247
|
+
|----------------------|--------------------------------------------------------------------------------------------|-----------------------------------------------------------------------------------------------------------------------------------|
|
|
248
|
+
| `validate_bool` | Boolean, optionally against an exact expected value. | [README_VALIDATE_BOOL](https://github.com/simplibs/simplibs-validate/blob/main/docs/validators/README_VALIDATE_BOOL.md) |
|
|
249
|
+
| `validate_container` | Any non-string container — length, uniqueness, membership, subset/superset, per-item rule. | [README_VALIDATE_CONTAINER](https://github.com/simplibs/simplibs-validate/blob/main/docs/validators/README_VALIDATE_CONTAINER.md) |
|
|
250
|
+
| `validate_float` | Float — comparisons, range, approximate equality, finiteness. | [README_VALIDATE_FLOAT](https://github.com/simplibs/simplibs-validate/blob/main/docs/validators/README_VALIDATE_FLOAT.md) |
|
|
251
|
+
| `validate_int` | Integer — comparisons, range, divisibility, remainder. | [README_VALIDATE_INT](https://github.com/simplibs/simplibs-validate/blob/main/docs/validators/README_VALIDATE_INT.md) |
|
|
252
|
+
| `validate_mapping` | `dict` — length, single/multiple key membership. | [README_VALIDATE_MAPPING](https://github.com/simplibs/simplibs-validate/blob/main/docs/validators/README_VALIDATE_MAPPING.md) |
|
|
253
|
+
| `validate_number` | Any number (`int`/`float`/`Decimal`/`complex`) — comparisons, range, membership. | [README_VALIDATE_NUMBER](https://github.com/simplibs/simplibs-validate/blob/main/docs/validators/README_VALIDATE_NUMBER.md) |
|
|
254
|
+
| `validate_string` | String — length, prefix/suffix/substring, regex, blankness, membership. | [README_VALIDATE_STRING](https://github.com/simplibs/simplibs-validate/blob/main/docs/validators/README_VALIDATE_STRING.md) |
|
|
255
|
+
| `validate_type` | Class/type object — subclass, identity, membership. | [README_VALIDATE_TYPE](https://github.com/simplibs/simplibs-validate/blob/main/docs/validators/README_VALIDATE_TYPE.md) |
|
|
256
|
+
|
|
257
|
+
Each `validate_*` is a thin wrapper: it composes its matching `*_rule(...)` factory and
|
|
258
|
+
calls `.validate()` on the result. For repeated validation against the same
|
|
259
|
+
constraints, build the rule once with `*_rule(...)` and reuse it, instead of calling
|
|
260
|
+
`validate_*` inside a loop.
|
|
261
|
+
|
|
262
|
+
---
|
|
263
|
+
|
|
264
|
+
## 🧩 The `Rule` Class
|
|
265
|
+
|
|
266
|
+
Every validation in this library, from the simplest type check to the most elaborate
|
|
267
|
+
composed constraint, is a `Rule`. It defines the minimal contract every concrete rule
|
|
268
|
+
implements (`is_valid`, `build_exception`), and builds a full evaluation interface on
|
|
269
|
+
top of it: `validate()`, the callable shorthand (`rule(value)`), operator composition
|
|
270
|
+
(`|`, `&`, `~`), and `annotated()` — the bridge into Python's own typing system.
|
|
271
|
+
|
|
272
|
+
```python
|
|
273
|
+
class Rule(ABC):
|
|
274
|
+
|
|
275
|
+
# ----------------------------------------------------------------------
|
|
276
|
+
# 1) Abstract Interface (mandatory for subclasses)
|
|
277
|
+
# ----------------------------------------------------------------------
|
|
278
|
+
|
|
279
|
+
@abstractmethod
|
|
280
|
+
def is_valid(
|
|
281
|
+
self,
|
|
282
|
+
value: Any,
|
|
283
|
+
) -> bool:
|
|
284
|
+
"""Return True if the tested value satisfies the rule, otherwise False."""
|
|
285
|
+
raise NotImplementedError
|
|
286
|
+
|
|
287
|
+
@abstractmethod
|
|
288
|
+
def build_exception(
|
|
289
|
+
self,
|
|
290
|
+
value: Any,
|
|
291
|
+
value_name: str | None = None,
|
|
292
|
+
context: str | None = None,
|
|
293
|
+
) -> Exception:
|
|
294
|
+
"""Create and return an exception instance (SimpleException) describing the validation failure."""
|
|
295
|
+
raise NotImplementedError
|
|
296
|
+
|
|
297
|
+
# ----------------------------------------------------------------------
|
|
298
|
+
# 2) Public Interface & Evaluation Logic
|
|
299
|
+
# ----------------------------------------------------------------------
|
|
300
|
+
|
|
301
|
+
def __call__(
|
|
302
|
+
self,
|
|
303
|
+
value: Any,
|
|
304
|
+
) -> bool:
|
|
305
|
+
"""Allow using the rule instance directly as a predicate function."""
|
|
306
|
+
return self.is_valid(value)
|
|
307
|
+
|
|
308
|
+
def validate(
|
|
309
|
+
self,
|
|
310
|
+
value: Any,
|
|
311
|
+
*,
|
|
312
|
+
value_name: str | None = None,
|
|
313
|
+
context: str | None = None,
|
|
314
|
+
return_bool: bool = False,
|
|
315
|
+
return_value: bool = False,
|
|
316
|
+
) -> Any:
|
|
317
|
+
"""Validate a value against this rule."""
|
|
318
|
+
if self.is_valid(value):
|
|
319
|
+
return value if return_value else True
|
|
320
|
+
|
|
321
|
+
if return_bool:
|
|
322
|
+
return False
|
|
323
|
+
|
|
324
|
+
raise self.build_exception(
|
|
325
|
+
value,
|
|
326
|
+
value_name=value_name,
|
|
327
|
+
context=context,
|
|
328
|
+
)
|
|
329
|
+
|
|
330
|
+
# ----------------------------------------------------------------------
|
|
331
|
+
# 3) Typing Integration
|
|
332
|
+
# ----------------------------------------------------------------------
|
|
333
|
+
|
|
334
|
+
def annotated(self, type_: type) -> Any:
|
|
335
|
+
"""Wrap this rule as `typing.Annotated[type_, self]` for type hints."""
|
|
336
|
+
return Annotated[type_, self]
|
|
337
|
+
|
|
338
|
+
# ----------------------------------------------------------------------
|
|
339
|
+
# 4) Operator-Based Composition (|, &, ~)
|
|
340
|
+
# ----------------------------------------------------------------------
|
|
341
|
+
|
|
342
|
+
def __or__(self, other: "Rule | Callable[[Any], bool]") -> "Rule":
|
|
343
|
+
"""Combine with another rule/callable via logical OR: `rule1 | rule2`."""
|
|
344
|
+
return AnyOf(self, other)
|
|
345
|
+
|
|
346
|
+
def __ror__(self, other: "Rule | Callable[[Any], bool]") -> "Rule":
|
|
347
|
+
"""Support `other | rule` when `other` has no (or a declining) `__or__`."""
|
|
348
|
+
return AnyOf(other, self)
|
|
349
|
+
|
|
350
|
+
def __and__(self, other: "Rule | Callable[[Any], bool]") -> "Rule":
|
|
351
|
+
"""Combine with another rule/callable via logical AND: `rule1 & rule2`."""
|
|
352
|
+
return AllOf(self, other)
|
|
353
|
+
|
|
354
|
+
def __rand__(self, other: "Rule | Callable[[Any], bool]") -> "Rule":
|
|
355
|
+
"""Support `other & rule` when `other` has no (or a declining) `__and__`."""
|
|
356
|
+
return AllOf(other, self)
|
|
357
|
+
|
|
358
|
+
def __invert__(self) -> "Rule":
|
|
359
|
+
"""Negate this rule via `~rule`. Equivalent to `Not(self)`."""
|
|
360
|
+
return Not(self)
|
|
361
|
+
```
|
|
362
|
+
|
|
363
|
+
➡️ Full method-by-method reference: [README_RULE_CLASS](https://github.com/simplibs/simplibs-validate/blob/main/docs/rules/README_RULE_CLASS.md)
|
|
364
|
+
|
|
365
|
+
---
|
|
366
|
+
|
|
367
|
+
## 📖 Rule Quick Reference
|
|
368
|
+
|
|
369
|
+
Every built-in `Rule` is exposed two ways: as its **class** (`IsInteger`), and as a
|
|
370
|
+
**snake_case shortcut** (`is_integer`) — a pre-instantiated object for zero-parameter
|
|
371
|
+
rules, or the class itself for parameterized ones. Both are fully interchangeable and
|
|
372
|
+
compose identically with `|`/`&`/`~`.
|
|
373
|
+
|
|
374
|
+
```python
|
|
375
|
+
validate(value, is_integer & greater_than(0))
|
|
376
|
+
# is exactly equivalent to:
|
|
377
|
+
validate(value, IsInteger() & GreaterThan(0))
|
|
378
|
+
```
|
|
379
|
+
|
|
380
|
+
Every rule below also has a `rule_class.<Name>` entry (for `isinstance` checks,
|
|
381
|
+
subclassing, or programmatic construction) and a `rules.<shortcut>` namespace entry —
|
|
382
|
+
both point at the same underlying object/class as the direct import.
|
|
383
|
+
|
|
384
|
+
### `containers/` — composing other rules
|
|
385
|
+
|
|
386
|
+
| Class | Shortcut | Params |
|
|
387
|
+
|-----------|------------|--------------------------------------------------------------------------------------|
|
|
388
|
+
| `AllOf` | `all_of` | `*rules: Union[Rule, Callable[[Any], bool]]` |
|
|
389
|
+
| `AnyOf` | `any_of` | `*rules: Union[Rule, Callable[[Any], bool]]` |
|
|
390
|
+
| `Compose` | `compose` | `transformer: Callable[[Any], Any]`, `validator: Union[Rule, Callable[[Any], bool]]` |
|
|
391
|
+
| `ForEach` | `for_each` | `rule: Union[Rule, Callable[[Any], bool]]` |
|
|
392
|
+
| `NoneOf` | `none_of` | `*rules: Union[Rule, Callable[[Any], bool]]` |
|
|
393
|
+
| `Not` | `negate` | `rule: Callable[[Any], bool]` |
|
|
394
|
+
|
|
395
|
+
➡️ [README_RULE_CONTAINERS](https://github.com/simplibs/simplibs-validate/blob/main/docs/rules/README_RULE_CONTAINERS.md)
|
|
396
|
+
|
|
397
|
+
### `predicates/arithmetic/` — numeric relationships
|
|
398
|
+
|
|
399
|
+
| Class | Shortcut | Params |
|
|
400
|
+
|----------------|-----------------|------------------------------------------------------------------------------------|
|
|
401
|
+
| `CloseTo` | `close_to` | `target: Union[float, int]`, `*`, `rel_tol: float = 1e-9`, `abs_tol: float = 0.0` |
|
|
402
|
+
| `DivisibleBy` | `divisible_by` | `divisor: int` |
|
|
403
|
+
| `HasRemainder` | `has_remainder` | `divisor: int`, `remainder: int` |
|
|
404
|
+
|
|
405
|
+
➡️ [README_RULE_PREDICATE_ARITHMETIC](https://github.com/simplibs/simplibs-validate/blob/main/docs/rules/README_RULE_PREDICATE_ARITHMETIC.md)
|
|
406
|
+
|
|
407
|
+
### `predicates/checkers/` — basic state & identity
|
|
408
|
+
|
|
409
|
+
| Class | Shortcut | Params |
|
|
410
|
+
|------------|-------------|--------|
|
|
411
|
+
| `IsEmpty` | `is_empty` | `-` |
|
|
412
|
+
| `IsFalse` | `is_false` | `-` |
|
|
413
|
+
| `IsNone` | `is_none` | `-` |
|
|
414
|
+
| `IsTrue` | `is_true` | `-` |
|
|
415
|
+
| `NotEmpty` | `not_empty` | `-` |
|
|
416
|
+
|
|
417
|
+
➡️ [README_RULE_PREDICATE_CHECKERS](https://github.com/simplibs/simplibs-validate/blob/main/docs/rules/README_RULE_PREDICATE_CHECKERS.md)
|
|
418
|
+
|
|
419
|
+
### `predicates/collections/` — containers, mappings & iterables
|
|
420
|
+
|
|
421
|
+
| Class | Shortcut | Params |
|
|
422
|
+
|----------------|------------------|------------------------------|
|
|
423
|
+
| `AllUnique` | `all_unique` | `-` |
|
|
424
|
+
| `HasItem` | `has_item` | `item: Any` |
|
|
425
|
+
| `HasKey` | `has_key` | `key: Any` |
|
|
426
|
+
| `HasKeys` | `has_keys` | `*keys: Any` |
|
|
427
|
+
| `IsContainer` | `is_container` | `-` |
|
|
428
|
+
| `IsSubsetOf` | `is_subset_of` | `reference: Collection[Any]` |
|
|
429
|
+
| `IsSupersetOf` | `is_superset_of` | `reference: Collection[Any]` |
|
|
430
|
+
|
|
431
|
+
➡️ [README_RULE_PREDICATE_COLLECTIONS](https://github.com/simplibs/simplibs-validate/blob/main/docs/rules/README_RULE_PREDICATE_COLLECTIONS.md)
|
|
432
|
+
|
|
433
|
+
### `predicates/comparisons/` — ordering & equality
|
|
434
|
+
|
|
435
|
+
| Class | Shortcut(s) | Params |
|
|
436
|
+
|------------------|--------------------------|----------------------------------------------------------------------------------------|
|
|
437
|
+
| `Equals` | `equals`, `eq` | `expected_value: Any` |
|
|
438
|
+
| `NotEquals` | `not_equals`, `ne` | `forbidden: Any` |
|
|
439
|
+
| `GreaterThan` | `greater_than`, `gt` | `threshold: Any` |
|
|
440
|
+
| `GreaterOrEqual` | `greater_or_equal`, `ge` | `threshold: Any` |
|
|
441
|
+
| `LessThan` | `less_than`, `lt` | `threshold: Any` |
|
|
442
|
+
| `LessOrEqual` | `less_or_equal`, `le` | `threshold: Any` |
|
|
443
|
+
| `InRange` | `in_range` | `min_val: Any`, `max_val: Any`, `include_min: bool = True`, `include_max: bool = True` |
|
|
444
|
+
|
|
445
|
+
➡️ [README_RULE_PREDICATE_COMPARISONS](https://github.com/simplibs/simplibs-validate/blob/main/docs/rules/README_RULE_PREDICATE_COMPARISONS.md)
|
|
446
|
+
|
|
447
|
+
### `predicates/introspection/` — structural & reflective checks
|
|
448
|
+
|
|
449
|
+
| Class | Shortcut(s) | Params |
|
|
450
|
+
|----------------|-----------------------------|-------------------------------------------------------------------------------|
|
|
451
|
+
| `IsInstance` | `is_instance` | `*types: type` |
|
|
452
|
+
| `IsType` | `is_type` | `-` |
|
|
453
|
+
| `IsSubclass` | `is_subclass` | `*types: type` |
|
|
454
|
+
| `IsDataclass` | `is_dataclass` | `-` |
|
|
455
|
+
| `IsCallable` | `is_callable` | `-` |
|
|
456
|
+
| `IsHashable` | `is_hashable` | `-` |
|
|
457
|
+
| `IsIterable` | `is_iterable` | `-` |
|
|
458
|
+
| `HasAttribute` | `has_attribute`, `has_attr` | `attr_name: str` |
|
|
459
|
+
| `HasLength` | `has_length` | `length: int = None`, `*`, `min_length: int = None`, `max_length: int = None` |
|
|
460
|
+
|
|
461
|
+
➡️ [README_RULE_PREDICATE_INTROSPECTION](https://github.com/simplibs/simplibs-validate/blob/main/docs/rules/README_RULE_PREDICATE_INTROSPECTION.md)
|
|
462
|
+
|
|
463
|
+
### `predicates/logic/` — identity, membership & custom predicates
|
|
464
|
+
|
|
465
|
+
| Class | Shortcut(s) | Params |
|
|
466
|
+
|------------|----------------------|---------------------------------------------------|
|
|
467
|
+
| `Is` | `same_as`, `is_same` | `expected: Any` |
|
|
468
|
+
| `IsNot` | `is_not` | `forbidden: Any` |
|
|
469
|
+
| `IsIn` | `is_in` | `options: Container[Any]`, `strict: bool = False` |
|
|
470
|
+
| `NotIn` | `not_in` | `options: Container[Any]`, `strict: bool = False` |
|
|
471
|
+
| `UserRule` | `user_rule` | `rule: Callable[[Any], bool]` |
|
|
472
|
+
|
|
473
|
+
➡️ [README_RULE_PREDICATE_LOGIC](https://github.com/simplibs/simplibs-validate/blob/main/docs/rules/README_RULE_PREDICATE_LOGIC.md)
|
|
474
|
+
|
|
475
|
+
> 💡 `Is`/`Not` are Python keywords and can't be used as identifiers directly — their
|
|
476
|
+
> shortcuts (`same_as`, `negate`) use a descriptive alternative instead.
|
|
477
|
+
|
|
478
|
+
### `predicates/numeric/` — numeric type identity
|
|
479
|
+
|
|
480
|
+
| Class | Shortcut(s) | Params |
|
|
481
|
+
|---------------------|------------------------|-----------------------|
|
|
482
|
+
| `IsBool` | `is_bool` | `-` |
|
|
483
|
+
| `IsInteger` | `is_integer`, `is_int` | `-` |
|
|
484
|
+
| `IsFloat` | `is_float` | `-` |
|
|
485
|
+
| `IsDecimal` | `is_decimal` | `-` |
|
|
486
|
+
| `IsNumber` | `is_number` | `-` |
|
|
487
|
+
| `IsPrimitiveNumber` | `is_primitive_number` | `-` |
|
|
488
|
+
| `IsZero` | `is_zero` | `-` |
|
|
489
|
+
| `IsNan` | `is_nan` | `-` |
|
|
490
|
+
| `IsInfinity` | `is_infinity` | `-` |
|
|
491
|
+
| `IsPi` | `is_pi` | `decimal_places: int` |
|
|
492
|
+
|
|
493
|
+
➡️ [README_RULE_PREDICATE_NUMERIC](https://github.com/simplibs/simplibs-validate/blob/main/docs/rules/README_RULE_PREDICATE_NUMERIC.md)
|
|
494
|
+
|
|
495
|
+
### `predicates/strings/` — string content
|
|
496
|
+
|
|
497
|
+
| Class | Shortcut(s) | Params |
|
|
498
|
+
|-----------------|-----------------------|----------------------|
|
|
499
|
+
| `IsString` | `is_string`, `is_str` | `-` |
|
|
500
|
+
| `Contains` | `contains` | `substring: str` |
|
|
501
|
+
| `IsSubstringOf` | `is_substring_of` | `target_string: str` |
|
|
502
|
+
| `StartsWith` | `starts_with` | `prefix: str` |
|
|
503
|
+
| `EndsWith` | `ends_with` | `suffix: str` |
|
|
504
|
+
| `Regex` | `regex` | `pattern: str` |
|
|
505
|
+
| `IsBlank` | `is_blank` | `-` |
|
|
506
|
+
| `NotBlank` | `not_blank` | `-` |
|
|
507
|
+
|
|
508
|
+
➡️ [README_RULE_PREDICATE_STRINGS](https://github.com/simplibs/simplibs-validate/blob/main/docs/rules/README_RULE_PREDICATE_STRINGS.md)
|
|
509
|
+
|
|
510
|
+
### `typing/` — annotation-driven validation
|
|
511
|
+
|
|
512
|
+
| Class | Shortcut(s) | Params |
|
|
513
|
+
|------------|-------------------------|-------------------|
|
|
514
|
+
| `IsAny` | `is_any`, `always_true` | `-` |
|
|
515
|
+
| `~IsAny` | `always_false` | `-` |
|
|
516
|
+
| `IsTyping` | `is_typing` | `annotation: Any` |
|
|
517
|
+
|
|
518
|
+
`IsTyping` recursively decomposes an arbitrary type annotation (`list[int]`, `dict[str,
|
|
519
|
+
int] | None`, `Literal[...]`, `Callable[...]`, ...) into a composed `Rule` tree —
|
|
520
|
+
the mechanism behind `validate_call`/`validate_dataclass`.
|
|
521
|
+
|
|
522
|
+
➡️ [README_RULE_TYPING](https://github.com/simplibs/simplibs-validate/blob/main/docs/rules/README_RULE_TYPING.md) — the public `IsTyping`/`build_typing_rule` entry points
|
|
523
|
+
➡️ [README_RULE_TYPING_BUILDERS](https://github.com/simplibs/simplibs-validate/blob/main/docs/rules/README_RULE_TYPING_BUILDERS.md) — the internal per-construct decomposition engine
|
|
524
|
+
|
|
525
|
+
---
|
|
526
|
+
|
|
527
|
+
## 🧰 Tools
|
|
528
|
+
|
|
529
|
+
Beyond individual rules, the `tools` package provides the decorators and helpers that
|
|
530
|
+
make validation part of a function's or dataclass's own definition:
|
|
531
|
+
|
|
532
|
+
* **`validate_call`** — validates a function's arguments (and optionally its return
|
|
533
|
+
value) against its own type annotations, on every call. Supports selective
|
|
534
|
+
validation (`check`), extra constraints (`overrides`), and a per-call bypass switch.
|
|
535
|
+
* **`validate_dataclass`** — the `@dataclass` counterpart: validates every field
|
|
536
|
+
against its annotation on instance construction, before any field is assigned.
|
|
537
|
+
* **`validated_type`** — names a reusable `Annotated[type, rule(s)]` combination once,
|
|
538
|
+
for use across multiple annotations.
|
|
539
|
+
* **`override_rules`** — batch-builds the `overrides=` mapping `validate_call`/
|
|
540
|
+
`validate_dataclass` expect, from keyword arguments.
|
|
541
|
+
* **`log_this`** — gives any function entry/exit/timing/exception logging, entirely
|
|
542
|
+
independent of validation, without imposing any logging configuration of its own.
|
|
543
|
+
|
|
544
|
+
➡️ [README_TOOLS](https://github.com/simplibs/simplibs-validate/blob/main/docs/tools/README_TOOLS.md)
|
|
545
|
+
|
|
546
|
+
---
|
|
547
|
+
|
|
548
|
+
## ⚠️ Exceptions
|
|
549
|
+
|
|
550
|
+
Every exception raised by `simplibs-validate` is built on top of
|
|
551
|
+
[`simplibs.exception.SimpleException`](https://pypi.org/project/simplibs-exception/) —
|
|
552
|
+
structured, readable diagnostic cards instead of a bare traceback.
|
|
553
|
+
|
|
554
|
+
The library's single common root is `ValidateError`:
|
|
555
|
+
|
|
556
|
+
```python
|
|
557
|
+
class ValidateError(SimpleException):
|
|
558
|
+
"""Root exception class for all errors originating from simplibs-validate."""
|
|
559
|
+
skip_locations = ("simplibs/validate",)
|
|
560
|
+
```
|
|
561
|
+
|
|
562
|
+
Two concrete subclasses distinguish *what kind* of mistake occurred:
|
|
563
|
+
|
|
564
|
+
| Exception | When it happens |
|
|
565
|
+
|-------------------|----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
|
|
566
|
+
| `ParamError` | A **developer error** made while constructing a rule or configuring a decorator — e.g. `HasLength()` with no length source, `validate_call(check=("x",))` where `x` has no annotation or override. |
|
|
567
|
+
| `ValidationError` | An **invalid runtime value** — the value being checked simply doesn't satisfy the rule. This is the exception you'll encounter during ordinary, everyday use. |
|
|
568
|
+
|
|
569
|
+
```python
|
|
570
|
+
try:
|
|
571
|
+
validate(-5, greater_than(0))
|
|
572
|
+
except ValidateError as e:
|
|
573
|
+
print(e) # a structured diagnostic card: what, why, how to fix it
|
|
574
|
+
```
|
|
575
|
+
|
|
576
|
+
Catching `ValidateError` catches both categories at once; catching `ValidationError`
|
|
577
|
+
or `ParamError` specifically lets you distinguish "bad input data" from "the
|
|
578
|
+
validation itself was set up incorrectly." `ValidateError.skip_locations` also filters
|
|
579
|
+
the library's own internal frames out of the error's reported location — the message
|
|
580
|
+
points to *your* code, not this library's implementation.
|
|
581
|
+
|
|
582
|
+
---
|
|
583
|
+
|
|
584
|
+
## 🧪 Testing Utilities
|
|
585
|
+
|
|
586
|
+
`simplibs-validate` ships with the same testing infrastructure it uses on itself —
|
|
587
|
+
useful if you're writing a custom `Rule` subclass or your own `validate_*` wrapper and
|
|
588
|
+
want thorough coverage without hand-writing every check.
|
|
589
|
+
|
|
590
|
+
* **`assert_rule_contract`** — the master facade for testing a `Rule` subclass: one
|
|
591
|
+
call runs the full deterministic battery (`is_valid`/`__call__`, the `validate()`
|
|
592
|
+
return-mode matrix, `build_exception()`'s diagnostic card contract), plus optional
|
|
593
|
+
constructor `ParamError` and `raise_invalid()` consistency checks.
|
|
594
|
+
* **`assert_validate_wrapper`** — verifies a `validate_*` convenience function
|
|
595
|
+
correctly wraps its underlying `*_rule` factory and delegates properly to
|
|
596
|
+
`Rule.validate()` — signature alignment, successful/failed delegation, both return
|
|
597
|
+
modes.
|
|
598
|
+
|
|
599
|
+
➡️ [README_TESTING_ASSERTS_RULE_CONTRACT](https://github.com/simplibs/simplibs-validate/blob/main/docs/testing/README_TESTING_ASSERTS_RULE_CONTRACT.md)
|
|
600
|
+
➡️ [README_TESTING_ASSERTS_VALIDATE_WARPER](https://github.com/simplibs/simplibs-validate/blob/main/docs/testing/README_TESTING_ASSERTS_VALIDATE_WARPER.md)
|
|
601
|
+
|
|
602
|
+
|
|
603
|
+
---
|
|
604
|
+
|
|
605
|
+
## 🔭 About the library, from the author's point of view
|
|
606
|
+
|
|
607
|
+
This is the **first version** of `simplibs-validate` — a deliberately focused core
|
|
608
|
+
(the `Rule` contract, its composition operators, the annotation-decomposition engine,
|
|
609
|
+
and the decorators built on top of it) designed with room to grow, rather than an
|
|
610
|
+
attempt to anticipate every possible validation need up front. Real-world use will
|
|
611
|
+
show, over time, which additional rules, builders, or tools are worth adding — the
|
|
612
|
+
architecture (small, atomized rule classes; a shared `Rule` contract; a single
|
|
613
|
+
recursive decomposition entry point for typing) was chosen specifically so that
|
|
614
|
+
growth stays easy without ever needing to revisit what's already here.
|
|
615
|
+
|
|
616
|
+
---
|
|
617
|
+
|
|
618
|
+
## ☯️ About simplibs
|
|
619
|
+
|
|
620
|
+
All libraries in the **simplibs** (Simple Libraries) ecosystem share a common
|
|
621
|
+
engineering philosophy:
|
|
622
|
+
|
|
623
|
+
* **Dyslexia-friendly:**
|
|
624
|
+
We actively minimize cognitive load. Code is atomized into small, self-contained units,
|
|
625
|
+
files are named directly after the logical task they perform, and explanations describe
|
|
626
|
+
*why* something is designed, not just *what* it is.
|
|
627
|
+
* **Programmer's Zen:**
|
|
628
|
+
Nothing should be missing, and nothing should be superfluous. We value clean execution
|
|
629
|
+
paths and robust, understandable code architectures over rushed, messy feature sets.
|
|
630
|
+
* **Defensive Style:**
|
|
631
|
+
We actively anticipate edge cases and failure modes so that only safe operational paths
|
|
632
|
+
remain. Our code is built to degrade gracefully rather than crash unexpectedly.
|
|
633
|
+
* **Minimalism:**
|
|
634
|
+
Find the most direct path to the goal in as few operational steps as possible without
|
|
635
|
+
taking shortcuts on safety, readability, or completeness.
|
|
636
|
+
* **Code as Craft:**
|
|
637
|
+
Code should be pleasant to look at, readable at a glance, and evoke structural harmony.
|
|
638
|
+
We treat software engineering as a precision trade.
|
|
639
|
+
|
|
640
|
+
---
|
|
641
|
+
|
|
642
|
+
### 🤝 Contributing & Community
|
|
643
|
+
|
|
644
|
+
This is an **open-source project** built with love and care. We strongly believe in
|
|
645
|
+
community collaboration and welcome any feedback, bug reports, or feature ideas!
|
|
646
|
+
|
|
647
|
+
* **Want to contribute?** Feel free to open an Issue or submit a Pull Request.
|
|
648
|
+
* **Want to get in touch?** If you'd like to discuss the project further, collaborate,
|
|
649
|
+
or just say hello, feel free to open a GitHub Issue or start a Discussion.
|
|
650
|
+
|
|
651
|
+
---
|
|
652
|
+
|
|
653
|
+
### 📝 License
|
|
654
|
+
|
|
655
|
+
This library is released under the **MIT License**. Build great things!
|
|
656
|
+
|
|
657
|
+
---
|
|
658
|
+
|
|
659
|
+
[▲ Back to Top](#-simplibs-validate)
|