qnty 0.0.9__py3-none-any.whl → 0.1.1__py3-none-any.whl

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 (92) hide show
  1. qnty/__init__.py +2 -3
  2. qnty/constants/__init__.py +10 -0
  3. qnty/constants/numerical.py +18 -0
  4. qnty/constants/solvers.py +6 -0
  5. qnty/constants/tests.py +6 -0
  6. qnty/dimensions/__init__.py +23 -0
  7. qnty/dimensions/base.py +97 -0
  8. qnty/dimensions/field_dims.py +126 -0
  9. qnty/dimensions/field_dims.pyi +128 -0
  10. qnty/dimensions/signature.py +111 -0
  11. qnty/equations/__init__.py +1 -1
  12. qnty/equations/equation.py +118 -155
  13. qnty/equations/system.py +68 -65
  14. qnty/expressions/__init__.py +25 -46
  15. qnty/expressions/formatter.py +188 -0
  16. qnty/expressions/functions.py +46 -68
  17. qnty/expressions/nodes.py +540 -384
  18. qnty/expressions/types.py +70 -0
  19. qnty/problems/__init__.py +145 -0
  20. qnty/problems/composition.py +1101 -0
  21. qnty/problems/problem.py +737 -0
  22. qnty/problems/rules.py +145 -0
  23. qnty/problems/solving.py +1216 -0
  24. qnty/problems/validation.py +127 -0
  25. qnty/quantities/__init__.py +28 -5
  26. qnty/quantities/base_qnty.py +677 -0
  27. qnty/quantities/field_converters.py +24004 -0
  28. qnty/quantities/field_qnty.py +1012 -0
  29. qnty/{generated/setters.py → quantities/field_setter.py} +3071 -2961
  30. qnty/{generated/quantities.py → quantities/field_vars.py} +829 -444
  31. qnty/{generated/quantities.pyi → quantities/field_vars.pyi} +1289 -1290
  32. qnty/solving/manager.py +50 -44
  33. qnty/solving/order.py +181 -133
  34. qnty/solving/solvers/__init__.py +2 -9
  35. qnty/solving/solvers/base.py +27 -37
  36. qnty/solving/solvers/iterative.py +115 -135
  37. qnty/solving/solvers/simultaneous.py +93 -165
  38. qnty/units/__init__.py +1 -0
  39. qnty/{generated/units.py → units/field_units.py} +1700 -991
  40. qnty/units/field_units.pyi +2461 -0
  41. qnty/units/prefixes.py +58 -105
  42. qnty/units/registry.py +76 -89
  43. qnty/utils/__init__.py +16 -0
  44. qnty/utils/caching/__init__.py +23 -0
  45. qnty/utils/caching/manager.py +401 -0
  46. qnty/utils/error_handling/__init__.py +66 -0
  47. qnty/utils/error_handling/context.py +39 -0
  48. qnty/utils/error_handling/exceptions.py +96 -0
  49. qnty/utils/error_handling/handlers.py +171 -0
  50. qnty/utils/logging.py +4 -4
  51. qnty/utils/protocols.py +164 -0
  52. qnty/utils/scope_discovery.py +420 -0
  53. {qnty-0.0.9.dist-info → qnty-0.1.1.dist-info}/METADATA +1 -1
  54. qnty-0.1.1.dist-info/RECORD +60 -0
  55. qnty/_backup/problem_original.py +0 -1251
  56. qnty/_backup/quantity.py +0 -63
  57. qnty/codegen/cli.py +0 -125
  58. qnty/codegen/generators/data/unit_data.json +0 -8807
  59. qnty/codegen/generators/data_processor.py +0 -345
  60. qnty/codegen/generators/dimensions_gen.py +0 -434
  61. qnty/codegen/generators/doc_generator.py +0 -141
  62. qnty/codegen/generators/out/dimension_mapping.json +0 -974
  63. qnty/codegen/generators/out/dimension_metadata.json +0 -123
  64. qnty/codegen/generators/out/units_metadata.json +0 -223
  65. qnty/codegen/generators/quantities_gen.py +0 -159
  66. qnty/codegen/generators/setters_gen.py +0 -178
  67. qnty/codegen/generators/stubs_gen.py +0 -167
  68. qnty/codegen/generators/units_gen.py +0 -295
  69. qnty/expressions/cache.py +0 -94
  70. qnty/generated/dimensions.py +0 -514
  71. qnty/problem/__init__.py +0 -91
  72. qnty/problem/base.py +0 -142
  73. qnty/problem/composition.py +0 -385
  74. qnty/problem/composition_mixin.py +0 -382
  75. qnty/problem/equations.py +0 -413
  76. qnty/problem/metaclass.py +0 -302
  77. qnty/problem/reconstruction.py +0 -1016
  78. qnty/problem/solving.py +0 -180
  79. qnty/problem/validation.py +0 -64
  80. qnty/problem/variables.py +0 -239
  81. qnty/quantities/expression_quantity.py +0 -314
  82. qnty/quantities/quantity.py +0 -428
  83. qnty/quantities/typed_quantity.py +0 -215
  84. qnty/validation/__init__.py +0 -0
  85. qnty/validation/registry.py +0 -0
  86. qnty/validation/rules.py +0 -167
  87. qnty-0.0.9.dist-info/RECORD +0 -63
  88. /qnty/{codegen → extensions}/__init__.py +0 -0
  89. /qnty/{codegen/generators → extensions/integration}/__init__.py +0 -0
  90. /qnty/{codegen/generators/utils → extensions/plotting}/__init__.py +0 -0
  91. /qnty/{generated → extensions/reporting}/__init__.py +0 -0
  92. {qnty-0.0.9.dist-info → qnty-0.1.1.dist-info}/WHEEL +0 -0
qnty/problems/rules.py ADDED
@@ -0,0 +1,145 @@
1
+ """
2
+ Engineering problem checks and validation system.
3
+
4
+ This module provides a clean API for defining engineering code compliance checks,
5
+ warnings, and validation rules at the problem level rather than variable level.
6
+ """
7
+
8
+ from __future__ import annotations
9
+
10
+ import traceback
11
+ from dataclasses import dataclass
12
+ from typing import Any, Literal
13
+
14
+ from ..expressions import Expression
15
+ from ..quantities import FieldQnty, Quantity
16
+
17
+
18
+ @dataclass
19
+ class Rules:
20
+ """
21
+ Represents an engineering problem check (code compliance, validation, etc.).
22
+
23
+ Checks are defined at the EngineeringProblem class level and evaluated after solving.
24
+ They can represent code compliance rules, engineering judgment warnings, or
25
+ validation conditions.
26
+ """
27
+
28
+ condition: Expression
29
+ message: str
30
+ warning_type: str = "VALIDATION"
31
+ severity: Literal["INFO", "WARNING", "ERROR"] = "WARNING"
32
+ name: str | None = None
33
+
34
+ def __post_init__(self):
35
+ """Generate a name if not provided."""
36
+ if self.name is None:
37
+ self.name = f"{self.warning_type}_{self.severity}"
38
+
39
+ def evaluate(self, variables: dict[str, FieldQnty]) -> dict[str, Any] | None:
40
+ """
41
+ Evaluate the check condition and return a warning dict if condition is True.
42
+
43
+ Args:
44
+ variables: Dictionary of variable name -> FieldQnty object mappings
45
+
46
+ Returns:
47
+ Warning dictionary if condition is met, None otherwise
48
+ """
49
+ try:
50
+ # Evaluate the condition expression using qnty's evaluation system
51
+ result = self._evaluate_expression(self.condition, variables)
52
+
53
+ if result:
54
+ return {"type": self.warning_type, "severity": self.severity, "message": self.message, "check_name": self.name, "condition": str(self.condition)}
55
+
56
+ except Exception as e:
57
+ # If evaluation fails, return an error warning
58
+
59
+ return {
60
+ "type": "EVALUATION_ERROR",
61
+ "severity": "ERROR",
62
+ "message": f"Failed to evaluate check '{self.name}': {str(e)}",
63
+ "check_name": self.name,
64
+ "condition": str(self.condition),
65
+ "debug_info": f"Expression type: {type(self.condition)}, Variables: {list(variables.keys())}",
66
+ "traceback": traceback.format_exc(),
67
+ }
68
+
69
+ return None
70
+
71
+ def _evaluate_expression(self, expr: Expression, variables: dict[str, FieldQnty]) -> bool:
72
+ """
73
+ Evaluate a qnty expression with current variable values.
74
+
75
+ Args:
76
+ expr: The expression to evaluate
77
+ variables: Dictionary of variable name -> FieldQnty object mappings
78
+
79
+ Returns:
80
+ Boolean result of the expression evaluation
81
+ """
82
+ # Evaluate the expression using the qnty evaluation system
83
+ result = expr.evaluate(variables)
84
+
85
+ # Convert result to boolean based on type
86
+ return self._convert_result_to_bool(result)
87
+
88
+ def _convert_result_to_bool(self, result: Quantity) -> bool:
89
+ """
90
+ Convert an evaluation result to a boolean.
91
+
92
+ Args:
93
+ result: The result from expression evaluation
94
+
95
+ Returns:
96
+ Boolean interpretation of the result
97
+ """
98
+ # For qnty Quantity objects, check the value
99
+ if isinstance(result, Quantity) and result.value is not None:
100
+ return bool(result.value > 0.5)
101
+
102
+ # Fallback for any numeric types
103
+ try:
104
+ return bool(float(result) > 0.5) # type: ignore[arg-type]
105
+ except (TypeError, ValueError) as e:
106
+ raise ValueError(f"Cannot convert expression result to boolean: {result}") from e
107
+
108
+
109
+ def add_rule(condition: Expression, message: str, warning_type: str = "VALIDATION", severity: Literal["INFO", "WARNING", "ERROR"] = "WARNING", name: str | None = None) -> Rules:
110
+ """
111
+ Create a new engineering problem check.
112
+
113
+ This function is intended to be called at the class level when defining
114
+ EngineeringProblem subclasses. It creates Check objects that will be
115
+ automatically collected by the metaclass.
116
+
117
+ Args:
118
+ condition: A qnty Expression that evaluates to True when the check should trigger
119
+ message: Descriptive message explaining what the check means
120
+ warning_type: Category of check (e.g., "CODE_COMPLIANCE", "VALIDATION")
121
+ severity: Severity level of the check
122
+ name: Optional name for the check
123
+
124
+ Returns:
125
+ Check object that can be assigned to a class attribute
126
+
127
+ Example:
128
+ class MyProblem(EngineeringProblem):
129
+ # Variables...
130
+ P = Pressure(90, "psi")
131
+ t = Length(0.1, "inch")
132
+ D = Length(1.0, "inch")
133
+
134
+ # Checks defined at class level
135
+ thick_wall_check = add_check(
136
+ t.geq(D / 6),
137
+ "Thick wall condition detected - requires special consideration",
138
+ warning_type="CODE_COMPLIANCE",
139
+ severity="WARNING"
140
+ )
141
+ """
142
+ return Rules(condition=condition, message=message, warning_type=warning_type, severity=severity, name=name)
143
+
144
+
145
+ __all__ = ["add_rule"]