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.
- qnty/__init__.py +2 -3
- qnty/constants/__init__.py +10 -0
- qnty/constants/numerical.py +18 -0
- qnty/constants/solvers.py +6 -0
- qnty/constants/tests.py +6 -0
- qnty/dimensions/__init__.py +23 -0
- qnty/dimensions/base.py +97 -0
- qnty/dimensions/field_dims.py +126 -0
- qnty/dimensions/field_dims.pyi +128 -0
- qnty/dimensions/signature.py +111 -0
- qnty/equations/__init__.py +1 -1
- qnty/equations/equation.py +118 -155
- qnty/equations/system.py +68 -65
- qnty/expressions/__init__.py +25 -46
- qnty/expressions/formatter.py +188 -0
- qnty/expressions/functions.py +46 -68
- qnty/expressions/nodes.py +540 -384
- qnty/expressions/types.py +70 -0
- qnty/problems/__init__.py +145 -0
- qnty/problems/composition.py +1101 -0
- qnty/problems/problem.py +737 -0
- qnty/problems/rules.py +145 -0
- qnty/problems/solving.py +1216 -0
- qnty/problems/validation.py +127 -0
- qnty/quantities/__init__.py +28 -5
- qnty/quantities/base_qnty.py +677 -0
- qnty/quantities/field_converters.py +24004 -0
- qnty/quantities/field_qnty.py +1012 -0
- qnty/{generated/setters.py → quantities/field_setter.py} +3071 -2961
- qnty/{generated/quantities.py → quantities/field_vars.py} +829 -444
- qnty/{generated/quantities.pyi → quantities/field_vars.pyi} +1289 -1290
- qnty/solving/manager.py +50 -44
- qnty/solving/order.py +181 -133
- qnty/solving/solvers/__init__.py +2 -9
- qnty/solving/solvers/base.py +27 -37
- qnty/solving/solvers/iterative.py +115 -135
- qnty/solving/solvers/simultaneous.py +93 -165
- qnty/units/__init__.py +1 -0
- qnty/{generated/units.py → units/field_units.py} +1700 -991
- qnty/units/field_units.pyi +2461 -0
- qnty/units/prefixes.py +58 -105
- qnty/units/registry.py +76 -89
- qnty/utils/__init__.py +16 -0
- qnty/utils/caching/__init__.py +23 -0
- qnty/utils/caching/manager.py +401 -0
- qnty/utils/error_handling/__init__.py +66 -0
- qnty/utils/error_handling/context.py +39 -0
- qnty/utils/error_handling/exceptions.py +96 -0
- qnty/utils/error_handling/handlers.py +171 -0
- qnty/utils/logging.py +4 -4
- qnty/utils/protocols.py +164 -0
- qnty/utils/scope_discovery.py +420 -0
- {qnty-0.0.9.dist-info → qnty-0.1.1.dist-info}/METADATA +1 -1
- qnty-0.1.1.dist-info/RECORD +60 -0
- qnty/_backup/problem_original.py +0 -1251
- qnty/_backup/quantity.py +0 -63
- qnty/codegen/cli.py +0 -125
- qnty/codegen/generators/data/unit_data.json +0 -8807
- qnty/codegen/generators/data_processor.py +0 -345
- qnty/codegen/generators/dimensions_gen.py +0 -434
- qnty/codegen/generators/doc_generator.py +0 -141
- qnty/codegen/generators/out/dimension_mapping.json +0 -974
- qnty/codegen/generators/out/dimension_metadata.json +0 -123
- qnty/codegen/generators/out/units_metadata.json +0 -223
- qnty/codegen/generators/quantities_gen.py +0 -159
- qnty/codegen/generators/setters_gen.py +0 -178
- qnty/codegen/generators/stubs_gen.py +0 -167
- qnty/codegen/generators/units_gen.py +0 -295
- qnty/expressions/cache.py +0 -94
- qnty/generated/dimensions.py +0 -514
- qnty/problem/__init__.py +0 -91
- qnty/problem/base.py +0 -142
- qnty/problem/composition.py +0 -385
- qnty/problem/composition_mixin.py +0 -382
- qnty/problem/equations.py +0 -413
- qnty/problem/metaclass.py +0 -302
- qnty/problem/reconstruction.py +0 -1016
- qnty/problem/solving.py +0 -180
- qnty/problem/validation.py +0 -64
- qnty/problem/variables.py +0 -239
- qnty/quantities/expression_quantity.py +0 -314
- qnty/quantities/quantity.py +0 -428
- qnty/quantities/typed_quantity.py +0 -215
- qnty/validation/__init__.py +0 -0
- qnty/validation/registry.py +0 -0
- qnty/validation/rules.py +0 -167
- qnty-0.0.9.dist-info/RECORD +0 -63
- /qnty/{codegen → extensions}/__init__.py +0 -0
- /qnty/{codegen/generators → extensions/integration}/__init__.py +0 -0
- /qnty/{codegen/generators/utils → extensions/plotting}/__init__.py +0 -0
- /qnty/{generated → extensions/reporting}/__init__.py +0 -0
- {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"]
|