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.
Files changed (205) hide show
  1. simplibs_validate-0.1.0/LICENSE +21 -0
  2. simplibs_validate-0.1.0/PKG-INFO +659 -0
  3. simplibs_validate-0.1.0/README.md +630 -0
  4. simplibs_validate-0.1.0/pyproject.toml +63 -0
  5. simplibs_validate-0.1.0/setup.cfg +4 -0
  6. simplibs_validate-0.1.0/src/simplibs/validate/__init__.py +46 -0
  7. simplibs_validate-0.1.0/src/simplibs/validate/exceptions/ParamError.py +31 -0
  8. simplibs_validate-0.1.0/src/simplibs/validate/exceptions/ValidateError.py +44 -0
  9. simplibs_validate-0.1.0/src/simplibs/validate/exceptions/ValidationError.py +30 -0
  10. simplibs_validate-0.1.0/src/simplibs/validate/exceptions/__init__.py +31 -0
  11. simplibs_validate-0.1.0/src/simplibs/validate/exceptions/build_validation_error.py +52 -0
  12. simplibs_validate-0.1.0/src/simplibs/validate/raise_invalid.py +84 -0
  13. simplibs_validate-0.1.0/src/simplibs/validate/rules/__init__.py +855 -0
  14. simplibs_validate-0.1.0/src/simplibs/validate/rules/base_class/Rule.py +280 -0
  15. simplibs_validate-0.1.0/src/simplibs/validate/rules/base_class/__init__.py +17 -0
  16. simplibs_validate-0.1.0/src/simplibs/validate/rules/containers/AllOf.py +147 -0
  17. simplibs_validate-0.1.0/src/simplibs/validate/rules/containers/AnyOf.py +146 -0
  18. simplibs_validate-0.1.0/src/simplibs/validate/rules/containers/Compose.py +148 -0
  19. simplibs_validate-0.1.0/src/simplibs/validate/rules/containers/ForEach.py +120 -0
  20. simplibs_validate-0.1.0/src/simplibs/validate/rules/containers/NoneOf.py +112 -0
  21. simplibs_validate-0.1.0/src/simplibs/validate/rules/containers/Not.py +97 -0
  22. simplibs_validate-0.1.0/src/simplibs/validate/rules/containers/__init__.py +28 -0
  23. simplibs_validate-0.1.0/src/simplibs/validate/rules/containers/_helpers/__init__.py +22 -0
  24. simplibs_validate-0.1.0/src/simplibs/validate/rules/containers/_helpers/as_predicate.py +78 -0
  25. simplibs_validate-0.1.0/src/simplibs/validate/rules/containers/_helpers/build_child_exception.py +39 -0
  26. simplibs_validate-0.1.0/src/simplibs/validate/rules/containers/_helpers/describe_rule.py +72 -0
  27. simplibs_validate-0.1.0/src/simplibs/validate/rules/containers/_init_validators/__init__.py +23 -0
  28. simplibs_validate-0.1.0/src/simplibs/validate/rules/containers/_init_validators/raise_container_param_not_type_error.py +53 -0
  29. simplibs_validate-0.1.0/src/simplibs/validate/rules/containers/_init_validators/raise_requires_at_least_one_rule_error.py +38 -0
  30. simplibs_validate-0.1.0/src/simplibs/validate/rules/containers/_init_validators/raise_rule_param_not_callable.py +55 -0
  31. simplibs_validate-0.1.0/src/simplibs/validate/rules/containers/_init_validators/validate_compose_param_is_callable.py +73 -0
  32. simplibs_validate-0.1.0/src/simplibs/validate/rules/predicates/__init__.py +87 -0
  33. simplibs_validate-0.1.0/src/simplibs/validate/rules/predicates/_helpers/__init__.py +18 -0
  34. simplibs_validate-0.1.0/src/simplibs/validate/rules/predicates/_helpers/accepts_one_positional_argument.py +127 -0
  35. simplibs_validate-0.1.0/src/simplibs/validate/rules/predicates/_helpers/format_container.py +50 -0
  36. simplibs_validate-0.1.0/src/simplibs/validate/rules/predicates/_init_validators/__init__.py +40 -0
  37. simplibs_validate-0.1.0/src/simplibs/validate/rules/predicates/_init_validators/rule_errors/__init__.py +21 -0
  38. simplibs_validate-0.1.0/src/simplibs/validate/rules/predicates/_init_validators/rule_errors/raise_has_length_param_conflict_error.py +54 -0
  39. simplibs_validate-0.1.0/src/simplibs/validate/rules/predicates/_init_validators/rule_errors/raise_regex_param_invalid_pattern_error.py +44 -0
  40. simplibs_validate-0.1.0/src/simplibs/validate/rules/predicates/_init_validators/rule_errors/raise_user_rule_param_wrong_arity.py +54 -0
  41. simplibs_validate-0.1.0/src/simplibs/validate/rules/predicates/_init_validators/shared_errors/__init__.py +32 -0
  42. simplibs_validate-0.1.0/src/simplibs/validate/rules/predicates/_init_validators/shared_errors/raise_param_min_max_bounds_inverted_error.py +79 -0
  43. simplibs_validate-0.1.0/src/simplibs/validate/rules/predicates/_init_validators/shared_errors/raise_param_min_max_incomparable_error.py +66 -0
  44. simplibs_validate-0.1.0/src/simplibs/validate/rules/predicates/_init_validators/shared_errors/raise_param_missing_error.py +78 -0
  45. simplibs_validate-0.1.0/src/simplibs/validate/rules/predicates/_init_validators/shared_errors/raise_param_not_callable_error.py +52 -0
  46. simplibs_validate-0.1.0/src/simplibs/validate/rules/predicates/_init_validators/shared_errors/raise_param_not_container_error.py +76 -0
  47. simplibs_validate-0.1.0/src/simplibs/validate/rules/predicates/_init_validators/shared_errors/raise_param_not_non_negative_integer_error.py +89 -0
  48. simplibs_validate-0.1.0/src/simplibs/validate/rules/predicates/_init_validators/shared_errors/raise_param_not_string_error.py +78 -0
  49. simplibs_validate-0.1.0/src/simplibs/validate/rules/predicates/_init_validators/shared_errors/raise_param_not_type_error.py +66 -0
  50. simplibs_validate-0.1.0/src/simplibs/validate/rules/predicates/_init_validators/shared_validators/__init__.py +24 -0
  51. simplibs_validate-0.1.0/src/simplibs/validate/rules/predicates/_init_validators/shared_validators/validate_param_is_integer.py +74 -0
  52. simplibs_validate-0.1.0/src/simplibs/validate/rules/predicates/_init_validators/shared_validators/validate_param_is_not_zero.py +70 -0
  53. simplibs_validate-0.1.0/src/simplibs/validate/rules/predicates/_init_validators/shared_validators/validate_param_is_primitive_number.py +77 -0
  54. simplibs_validate-0.1.0/src/simplibs/validate/rules/predicates/_init_validators/shared_validators/validate_param_remainder_in_range.py +59 -0
  55. simplibs_validate-0.1.0/src/simplibs/validate/rules/predicates/arithmetic/CloseTo.py +149 -0
  56. simplibs_validate-0.1.0/src/simplibs/validate/rules/predicates/arithmetic/DivisibleBy.py +120 -0
  57. simplibs_validate-0.1.0/src/simplibs/validate/rules/predicates/arithmetic/HasRemainder.py +137 -0
  58. simplibs_validate-0.1.0/src/simplibs/validate/rules/predicates/arithmetic/__init__.py +21 -0
  59. simplibs_validate-0.1.0/src/simplibs/validate/rules/predicates/checkers/IsEmpty.py +101 -0
  60. simplibs_validate-0.1.0/src/simplibs/validate/rules/predicates/checkers/IsFalse.py +81 -0
  61. simplibs_validate-0.1.0/src/simplibs/validate/rules/predicates/checkers/IsNone.py +81 -0
  62. simplibs_validate-0.1.0/src/simplibs/validate/rules/predicates/checkers/IsTrue.py +80 -0
  63. simplibs_validate-0.1.0/src/simplibs/validate/rules/predicates/checkers/NotEmpty.py +100 -0
  64. simplibs_validate-0.1.0/src/simplibs/validate/rules/predicates/checkers/__init__.py +25 -0
  65. simplibs_validate-0.1.0/src/simplibs/validate/rules/predicates/collections/AllUnique.py +124 -0
  66. simplibs_validate-0.1.0/src/simplibs/validate/rules/predicates/collections/HasItem.py +132 -0
  67. simplibs_validate-0.1.0/src/simplibs/validate/rules/predicates/collections/HasKey.py +104 -0
  68. simplibs_validate-0.1.0/src/simplibs/validate/rules/predicates/collections/HasKeys.py +115 -0
  69. simplibs_validate-0.1.0/src/simplibs/validate/rules/predicates/collections/IsContainer.py +99 -0
  70. simplibs_validate-0.1.0/src/simplibs/validate/rules/predicates/collections/IsSubsetOf.py +139 -0
  71. simplibs_validate-0.1.0/src/simplibs/validate/rules/predicates/collections/IsSupersetOf.py +138 -0
  72. simplibs_validate-0.1.0/src/simplibs/validate/rules/predicates/collections/__init__.py +29 -0
  73. simplibs_validate-0.1.0/src/simplibs/validate/rules/predicates/comparisons/Equals.py +87 -0
  74. simplibs_validate-0.1.0/src/simplibs/validate/rules/predicates/comparisons/GreaterOrEqual.py +106 -0
  75. simplibs_validate-0.1.0/src/simplibs/validate/rules/predicates/comparisons/GreaterThan.py +106 -0
  76. simplibs_validate-0.1.0/src/simplibs/validate/rules/predicates/comparisons/InRange.py +166 -0
  77. simplibs_validate-0.1.0/src/simplibs/validate/rules/predicates/comparisons/LessOrEqual.py +106 -0
  78. simplibs_validate-0.1.0/src/simplibs/validate/rules/predicates/comparisons/LessThan.py +106 -0
  79. simplibs_validate-0.1.0/src/simplibs/validate/rules/predicates/comparisons/NotEquals.py +88 -0
  80. simplibs_validate-0.1.0/src/simplibs/validate/rules/predicates/comparisons/__init__.py +29 -0
  81. simplibs_validate-0.1.0/src/simplibs/validate/rules/predicates/introspection/HasAttribute.py +95 -0
  82. simplibs_validate-0.1.0/src/simplibs/validate/rules/predicates/introspection/HasLength.py +177 -0
  83. simplibs_validate-0.1.0/src/simplibs/validate/rules/predicates/introspection/IsCallable.py +81 -0
  84. simplibs_validate-0.1.0/src/simplibs/validate/rules/predicates/introspection/IsDataclass.py +84 -0
  85. simplibs_validate-0.1.0/src/simplibs/validate/rules/predicates/introspection/IsHashable.py +91 -0
  86. simplibs_validate-0.1.0/src/simplibs/validate/rules/predicates/introspection/IsInstance.py +105 -0
  87. simplibs_validate-0.1.0/src/simplibs/validate/rules/predicates/introspection/IsIterable.py +90 -0
  88. simplibs_validate-0.1.0/src/simplibs/validate/rules/predicates/introspection/IsSubclass.py +122 -0
  89. simplibs_validate-0.1.0/src/simplibs/validate/rules/predicates/introspection/IsType.py +82 -0
  90. simplibs_validate-0.1.0/src/simplibs/validate/rules/predicates/introspection/__init__.py +34 -0
  91. simplibs_validate-0.1.0/src/simplibs/validate/rules/predicates/logic/Is.py +88 -0
  92. simplibs_validate-0.1.0/src/simplibs/validate/rules/predicates/logic/IsIn.py +145 -0
  93. simplibs_validate-0.1.0/src/simplibs/validate/rules/predicates/logic/IsNot.py +89 -0
  94. simplibs_validate-0.1.0/src/simplibs/validate/rules/predicates/logic/NotIn.py +145 -0
  95. simplibs_validate-0.1.0/src/simplibs/validate/rules/predicates/logic/UserRule.py +118 -0
  96. simplibs_validate-0.1.0/src/simplibs/validate/rules/predicates/logic/__init__.py +24 -0
  97. simplibs_validate-0.1.0/src/simplibs/validate/rules/predicates/numeric/IsBool.py +96 -0
  98. simplibs_validate-0.1.0/src/simplibs/validate/rules/predicates/numeric/IsDecimal.py +83 -0
  99. simplibs_validate-0.1.0/src/simplibs/validate/rules/predicates/numeric/IsFloat.py +75 -0
  100. simplibs_validate-0.1.0/src/simplibs/validate/rules/predicates/numeric/IsInfinity.py +97 -0
  101. simplibs_validate-0.1.0/src/simplibs/validate/rules/predicates/numeric/IsInteger.py +118 -0
  102. simplibs_validate-0.1.0/src/simplibs/validate/rules/predicates/numeric/IsNan.py +98 -0
  103. simplibs_validate-0.1.0/src/simplibs/validate/rules/predicates/numeric/IsNumber.py +96 -0
  104. simplibs_validate-0.1.0/src/simplibs/validate/rules/predicates/numeric/IsPi.py +138 -0
  105. simplibs_validate-0.1.0/src/simplibs/validate/rules/predicates/numeric/IsPrimitiveNumber.py +87 -0
  106. simplibs_validate-0.1.0/src/simplibs/validate/rules/predicates/numeric/IsZero.py +109 -0
  107. simplibs_validate-0.1.0/src/simplibs/validate/rules/predicates/numeric/__init__.py +36 -0
  108. simplibs_validate-0.1.0/src/simplibs/validate/rules/predicates/strings/Contains.py +114 -0
  109. simplibs_validate-0.1.0/src/simplibs/validate/rules/predicates/strings/EndsWith.py +114 -0
  110. simplibs_validate-0.1.0/src/simplibs/validate/rules/predicates/strings/IsBlank.py +98 -0
  111. simplibs_validate-0.1.0/src/simplibs/validate/rules/predicates/strings/IsString.py +104 -0
  112. simplibs_validate-0.1.0/src/simplibs/validate/rules/predicates/strings/IsSubstringOf.py +114 -0
  113. simplibs_validate-0.1.0/src/simplibs/validate/rules/predicates/strings/NotBlank.py +98 -0
  114. simplibs_validate-0.1.0/src/simplibs/validate/rules/predicates/strings/Regex.py +126 -0
  115. simplibs_validate-0.1.0/src/simplibs/validate/rules/predicates/strings/StartsWith.py +114 -0
  116. simplibs_validate-0.1.0/src/simplibs/validate/rules/predicates/strings/__init__.py +30 -0
  117. simplibs_validate-0.1.0/src/simplibs/validate/rules/typing/IsAny.py +114 -0
  118. simplibs_validate-0.1.0/src/simplibs/validate/rules/typing/IsTyping.py +100 -0
  119. simplibs_validate-0.1.0/src/simplibs/validate/rules/typing/__init__.py +26 -0
  120. simplibs_validate-0.1.0/src/simplibs/validate/rules/typing/_builders/ORIGIN_TABLE.py +112 -0
  121. simplibs_validate-0.1.0/src/simplibs/validate/rules/typing/_builders/__init__.py +35 -0
  122. simplibs_validate-0.1.0/src/simplibs/validate/rules/typing/_builders/build_annotated_rule.py +106 -0
  123. simplibs_validate-0.1.0/src/simplibs/validate/rules/typing/_builders/build_any_of_rule.py +73 -0
  124. simplibs_validate-0.1.0/src/simplibs/validate/rules/typing/_builders/build_callable_rule.py +63 -0
  125. simplibs_validate-0.1.0/src/simplibs/validate/rules/typing/_builders/build_elements_rule.py +109 -0
  126. simplibs_validate-0.1.0/src/simplibs/validate/rules/typing/_builders/build_key_value_rule.py +65 -0
  127. simplibs_validate-0.1.0/src/simplibs/validate/rules/typing/_builders/build_literal_rule.py +60 -0
  128. simplibs_validate-0.1.0/src/simplibs/validate/rules/typing/_builders/build_tuple_rule.py +111 -0
  129. simplibs_validate-0.1.0/src/simplibs/validate/rules/typing/_builders/build_type_rule.py +114 -0
  130. simplibs_validate-0.1.0/src/simplibs/validate/rules/typing/_validations/__init__.py +16 -0
  131. simplibs_validate-0.1.0/src/simplibs/validate/rules/typing/_validations/raise_unsupported_annotation_error.py +64 -0
  132. simplibs_validate-0.1.0/src/simplibs/validate/rules/typing/build_typing_rule.py +131 -0
  133. simplibs_validate-0.1.0/src/simplibs/validate/rules/typing/tools/__init__.py +20 -0
  134. simplibs_validate-0.1.0/src/simplibs/validate/rules/typing/tools/get_supported_origins.py +42 -0
  135. simplibs_validate-0.1.0/src/simplibs/validate/rules/typing/tools/is_supported_annotation.py +60 -0
  136. simplibs_validate-0.1.0/src/simplibs/validate/testing/__init__.py +43 -0
  137. simplibs_validate-0.1.0/src/simplibs/validate/testing/assert_rule_contract.py +198 -0
  138. simplibs_validate-0.1.0/src/simplibs/validate/testing/assert_validate_wrapper.py +81 -0
  139. simplibs_validate-0.1.0/src/simplibs/validate/testing/asserts/__init__.py +27 -0
  140. simplibs_validate-0.1.0/src/simplibs/validate/testing/asserts/assert_rule_build_exception.py +149 -0
  141. simplibs_validate-0.1.0/src/simplibs/validate/testing/asserts/assert_rule_is_valid.py +90 -0
  142. simplibs_validate-0.1.0/src/simplibs/validate/testing/asserts/assert_rule_param_error.py +78 -0
  143. simplibs_validate-0.1.0/src/simplibs/validate/testing/asserts/assert_rule_raise_invalid.py +91 -0
  144. simplibs_validate-0.1.0/src/simplibs/validate/testing/asserts/assert_rule_validate.py +107 -0
  145. simplibs_validate-0.1.0/src/simplibs/validate/tools/__init__.py +33 -0
  146. simplibs_validate-0.1.0/src/simplibs/validate/tools/log_this/__init__.py +16 -0
  147. simplibs_validate-0.1.0/src/simplibs/validate/tools/log_this/_helpers/__init__.py +24 -0
  148. simplibs_validate-0.1.0/src/simplibs/validate/tools/log_this/_helpers/format_bound_arguments.py +65 -0
  149. simplibs_validate-0.1.0/src/simplibs/validate/tools/log_this/_helpers/get_context_info.py +34 -0
  150. simplibs_validate-0.1.0/src/simplibs/validate/tools/log_this/_helpers/log_exception.py +68 -0
  151. simplibs_validate-0.1.0/src/simplibs/validate/tools/log_this/_helpers/log_start.py +40 -0
  152. simplibs_validate-0.1.0/src/simplibs/validate/tools/log_this/_helpers/log_success.py +74 -0
  153. simplibs_validate-0.1.0/src/simplibs/validate/tools/log_this/log_this.py +232 -0
  154. simplibs_validate-0.1.0/src/simplibs/validate/tools/override_rules/__init__.py +15 -0
  155. simplibs_validate-0.1.0/src/simplibs/validate/tools/override_rules/_validations/__init__.py +14 -0
  156. simplibs_validate-0.1.0/src/simplibs/validate/tools/override_rules/_validations/raise_override_rules_invalid_error.py +51 -0
  157. simplibs_validate-0.1.0/src/simplibs/validate/tools/override_rules/override_rules.py +97 -0
  158. simplibs_validate-0.1.0/src/simplibs/validate/tools/validate_call/__init__.py +16 -0
  159. simplibs_validate-0.1.0/src/simplibs/validate/tools/validate_call/_helpers/__init__.py +24 -0
  160. simplibs_validate-0.1.0/src/simplibs/validate/tools/validate_call/_helpers/compile_parameter_rules.py +133 -0
  161. simplibs_validate-0.1.0/src/simplibs/validate/tools/validate_call/_helpers/compile_return_rule.py +75 -0
  162. simplibs_validate-0.1.0/src/simplibs/validate/tools/validate_call/_helpers/get_context_string.py +29 -0
  163. simplibs_validate-0.1.0/src/simplibs/validate/tools/validate_call/_helpers/is_bypass_parameter.py +68 -0
  164. simplibs_validate-0.1.0/src/simplibs/validate/tools/validate_call/_helpers/should_validate.py +68 -0
  165. simplibs_validate-0.1.0/src/simplibs/validate/tools/validate_call/_validations/__init__.py +19 -0
  166. simplibs_validate-0.1.0/src/simplibs/validate/tools/validate_call/_validations/raise_no_rule_for_checked_param.py +47 -0
  167. simplibs_validate-0.1.0/src/simplibs/validate/tools/validate_call/_validations/raise_no_rule_for_return.py +43 -0
  168. simplibs_validate-0.1.0/src/simplibs/validate/tools/validate_call/validate_call.py +335 -0
  169. simplibs_validate-0.1.0/src/simplibs/validate/tools/validate_dataclass/__init__.py +16 -0
  170. simplibs_validate-0.1.0/src/simplibs/validate/tools/validate_dataclass/_helpers/__init__.py +16 -0
  171. simplibs_validate-0.1.0/src/simplibs/validate/tools/validate_dataclass/_helpers/get_dataclass_context_string.py +30 -0
  172. simplibs_validate-0.1.0/src/simplibs/validate/tools/validate_dataclass/_validations/__init__.py +16 -0
  173. simplibs_validate-0.1.0/src/simplibs/validate/tools/validate_dataclass/_validations/raise_not_a_dataclass_error.py +44 -0
  174. simplibs_validate-0.1.0/src/simplibs/validate/tools/validate_dataclass/validate_dataclass.py +206 -0
  175. simplibs_validate-0.1.0/src/simplibs/validate/tools/validated_type/__init__.py +15 -0
  176. simplibs_validate-0.1.0/src/simplibs/validate/tools/validated_type/_validations/__init__.py +17 -0
  177. simplibs_validate-0.1.0/src/simplibs/validate/tools/validated_type/_validations/raise_validated_type_missing_rule_error.py +46 -0
  178. simplibs_validate-0.1.0/src/simplibs/validate/tools/validated_type/_validations/raise_validated_type_rule_invalid_error.py +47 -0
  179. simplibs_validate-0.1.0/src/simplibs/validate/tools/validated_type/validated_type.py +147 -0
  180. simplibs_validate-0.1.0/src/simplibs/validate/validate.py +145 -0
  181. simplibs_validate-0.1.0/src/simplibs/validate/validators/__init__.py +67 -0
  182. simplibs_validate-0.1.0/src/simplibs/validate/validators/rules/__init__.py +30 -0
  183. simplibs_validate-0.1.0/src/simplibs/validate/validators/rules/boolean_rule.py +88 -0
  184. simplibs_validate-0.1.0/src/simplibs/validate/validators/rules/container_rule.py +141 -0
  185. simplibs_validate-0.1.0/src/simplibs/validate/validators/rules/float_rule.py +172 -0
  186. simplibs_validate-0.1.0/src/simplibs/validate/validators/rules/integer_rule.py +161 -0
  187. simplibs_validate-0.1.0/src/simplibs/validate/validators/rules/mapping_rule.py +123 -0
  188. simplibs_validate-0.1.0/src/simplibs/validate/validators/rules/number_rule.py +136 -0
  189. simplibs_validate-0.1.0/src/simplibs/validate/validators/rules/string_rule.py +193 -0
  190. simplibs_validate-0.1.0/src/simplibs/validate/validators/rules/type_rule.py +104 -0
  191. simplibs_validate-0.1.0/src/simplibs/validate/validators/validate_bool.py +59 -0
  192. simplibs_validate-0.1.0/src/simplibs/validate/validators/validate_container.py +87 -0
  193. simplibs_validate-0.1.0/src/simplibs/validate/validators/validate_float.py +102 -0
  194. simplibs_validate-0.1.0/src/simplibs/validate/validators/validate_int.py +96 -0
  195. simplibs_validate-0.1.0/src/simplibs/validate/validators/validate_mapping.py +75 -0
  196. simplibs_validate-0.1.0/src/simplibs/validate/validators/validate_number.py +89 -0
  197. simplibs_validate-0.1.0/src/simplibs/validate/validators/validate_str.py +123 -0
  198. simplibs_validate-0.1.0/src/simplibs/validate/validators/validate_type.py +73 -0
  199. simplibs_validate-0.1.0/src/simplibs_validate.egg-info/PKG-INFO +659 -0
  200. simplibs_validate-0.1.0/src/simplibs_validate.egg-info/SOURCES.txt +203 -0
  201. simplibs_validate-0.1.0/src/simplibs_validate.egg-info/dependency_links.txt +1 -0
  202. simplibs_validate-0.1.0/src/simplibs_validate.egg-info/requires.txt +6 -0
  203. simplibs_validate-0.1.0/src/simplibs_validate.egg-info/top_level.txt +1 -0
  204. simplibs_validate-0.1.0/tests/test_raise_invalid.py +55 -0
  205. 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
+ [![PyPI](https://img.shields.io/pypi/v/simplibs-validate)](https://pypi.org/project/simplibs-validate/)
33
+ [![Python](https://img.shields.io/badge/python-3.11%2B-blue)](https://www.python.org/downloads/)
34
+ [![Licence](https://img.shields.io/badge/licence-MIT-green)](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)