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
@@ -0,0 +1,127 @@
|
|
1
|
+
"""
|
2
|
+
Problem-validation integration for Problem class.
|
3
|
+
|
4
|
+
This module provides validation functionality through a mixin pattern,
|
5
|
+
allowing Problems to run validation checks and collect warnings.
|
6
|
+
|
7
|
+
Key features:
|
8
|
+
- Type-safe validation check management
|
9
|
+
- Robust error handling for validation failures
|
10
|
+
- Integration with Problem metaclass system
|
11
|
+
- Proper closure handling to avoid late binding issues
|
12
|
+
"""
|
13
|
+
|
14
|
+
from __future__ import annotations
|
15
|
+
|
16
|
+
import logging
|
17
|
+
from collections.abc import Callable
|
18
|
+
from typing import Any, Protocol
|
19
|
+
|
20
|
+
|
21
|
+
class ValidationResult(Protocol):
|
22
|
+
"""Protocol for validation check results."""
|
23
|
+
|
24
|
+
def evaluate(self, variables: dict[str, Any]) -> dict[str, Any] | None:
|
25
|
+
"""Evaluate the validation check."""
|
26
|
+
...
|
27
|
+
|
28
|
+
|
29
|
+
class ProblemAttributes(Protocol):
|
30
|
+
"""Protocol defining expected attributes for validation mixin."""
|
31
|
+
|
32
|
+
logger: logging.Logger
|
33
|
+
warnings: list[dict[str, Any]]
|
34
|
+
validation_checks: list[Callable[[Any], dict[str, Any] | None]]
|
35
|
+
variables: dict[str, Any]
|
36
|
+
|
37
|
+
|
38
|
+
class ValidationMixin:
|
39
|
+
"""Mixin class providing validation functionality."""
|
40
|
+
|
41
|
+
# These attributes will be provided by other mixins in the final Problem class
|
42
|
+
logger: logging.Logger
|
43
|
+
warnings: list[dict[str, Any]]
|
44
|
+
validation_checks: list[Callable[[Any], dict[str, Any] | None]]
|
45
|
+
variables: dict[str, Any]
|
46
|
+
|
47
|
+
def add_validation_check(self, check_function: Callable[[Any], dict[str, Any] | None]) -> None:
|
48
|
+
"""Add a validation check function."""
|
49
|
+
if not callable(check_function):
|
50
|
+
raise TypeError("check_function must be callable")
|
51
|
+
self.validation_checks.append(check_function)
|
52
|
+
|
53
|
+
def validate(self) -> list[dict[str, Any]]:
|
54
|
+
"""Run all validation checks and return any warnings."""
|
55
|
+
validation_warnings: list[dict[str, Any]] = []
|
56
|
+
|
57
|
+
for check in self.validation_checks:
|
58
|
+
if not callable(check):
|
59
|
+
self.logger.warning(f"Skipping non-callable validation check: {check}")
|
60
|
+
continue
|
61
|
+
|
62
|
+
try:
|
63
|
+
result = check(self)
|
64
|
+
if result is not None and isinstance(result, dict):
|
65
|
+
validation_warnings.append(result)
|
66
|
+
elif result is not None:
|
67
|
+
self.logger.warning(f"Validation check returned non-dict result: {type(result)}")
|
68
|
+
except Exception as e:
|
69
|
+
self.logger.debug(f"Validation check failed: {e}")
|
70
|
+
|
71
|
+
return validation_warnings
|
72
|
+
|
73
|
+
def get_warnings(self) -> list[dict[str, Any]]:
|
74
|
+
"""Get all warnings from the problem."""
|
75
|
+
try:
|
76
|
+
warnings = self.warnings.copy() if hasattr(self, "warnings") and self.warnings else []
|
77
|
+
except (AttributeError, TypeError):
|
78
|
+
warnings = []
|
79
|
+
self.logger.warning("Problem warnings attribute is not properly initialized")
|
80
|
+
|
81
|
+
try:
|
82
|
+
validation_warnings = self.validate()
|
83
|
+
warnings.extend(validation_warnings)
|
84
|
+
except Exception as e:
|
85
|
+
self.logger.error(f"Failed to run validation: {e}")
|
86
|
+
|
87
|
+
return warnings
|
88
|
+
|
89
|
+
def _recreate_validation_checks(self) -> None:
|
90
|
+
"""Collect and integrate validation checks from class-level Check objects."""
|
91
|
+
# Clear existing checks
|
92
|
+
self.validation_checks = []
|
93
|
+
|
94
|
+
# Safely get class checks
|
95
|
+
try:
|
96
|
+
class_checks: dict[str, ValidationResult] = getattr(self.__class__, "_class_checks", {})
|
97
|
+
except AttributeError:
|
98
|
+
self.logger.debug("No class checks found")
|
99
|
+
return
|
100
|
+
|
101
|
+
if not isinstance(class_checks, dict):
|
102
|
+
self.logger.warning(f"Expected dict for _class_checks, got {type(class_checks)}")
|
103
|
+
return
|
104
|
+
|
105
|
+
# Create validation functions from Check objects
|
106
|
+
for check_name, check_obj in class_checks.items():
|
107
|
+
if not hasattr(check_obj, "evaluate"):
|
108
|
+
self.logger.warning(f"Check object '{check_name}' missing 'evaluate' method")
|
109
|
+
continue
|
110
|
+
|
111
|
+
validation_function = self._create_validation_function(check_obj)
|
112
|
+
self.validation_checks.append(validation_function)
|
113
|
+
|
114
|
+
def _create_validation_function(self, check_obj: ValidationResult) -> Callable[[Any], dict[str, Any] | None]:
|
115
|
+
"""Create a validation function from a check object, avoiding closure issues."""
|
116
|
+
|
117
|
+
def check_function(problem_instance: Any) -> dict[str, Any] | None:
|
118
|
+
try:
|
119
|
+
if not hasattr(problem_instance, "variables"):
|
120
|
+
return None
|
121
|
+
return check_obj.evaluate(problem_instance.variables)
|
122
|
+
except Exception as e:
|
123
|
+
if hasattr(problem_instance, "logger"):
|
124
|
+
problem_instance.logger.debug(f"Validation check evaluation failed: {e}")
|
125
|
+
return None
|
126
|
+
|
127
|
+
return check_function
|
qnty/quantities/__init__.py
CHANGED
@@ -1,6 +1,29 @@
|
|
1
|
-
|
1
|
+
"""
|
2
|
+
Core Quantities Package
|
3
|
+
=====================
|
2
4
|
|
3
|
-
|
4
|
-
|
5
|
-
|
6
|
-
|
5
|
+
High-performance quantity and variable systems.
|
6
|
+
"""
|
7
|
+
|
8
|
+
from .base_qnty import Quantity
|
9
|
+
from .field_qnty import *
|
10
|
+
from .field_qnty import FieldQnty
|
11
|
+
from .field_vars import *
|
12
|
+
|
13
|
+
# Register types with TypeRegistry for performance optimization
|
14
|
+
try:
|
15
|
+
from ..utils.protocols import register_variable_type
|
16
|
+
|
17
|
+
register_variable_type(FieldQnty)
|
18
|
+
# Also register all generated field variable types
|
19
|
+
import inspect
|
20
|
+
import sys
|
21
|
+
|
22
|
+
current_module = sys.modules[__name__]
|
23
|
+
for _name, obj in inspect.getmembers(current_module, inspect.isclass):
|
24
|
+
if hasattr(obj, "_dimension") and issubclass(obj, FieldQnty):
|
25
|
+
register_variable_type(obj)
|
26
|
+
except ImportError:
|
27
|
+
pass # Handle import ordering gracefully
|
28
|
+
|
29
|
+
__all__ = ["Quantity", "FieldQnty"]
|