qnty 0.0.2__py3-none-any.whl → 0.0.4__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 +171 -2
- qnty/dimension.py +110 -12
- qnty/prefixes.py +229 -0
- qnty/unit.py +68 -0
- qnty/unit_types/__init__.py +0 -0
- qnty/unit_types/base.py +47 -0
- qnty/units.py +8079 -33
- qnty/variable.py +2 -1
- qnty/variable_types/__init__.py +0 -0
- qnty/variable_types/base.py +58 -0
- qnty/variable_types/expression_variable.py +68 -0
- qnty/variable_types/typed_variable.py +92 -0
- qnty/variables.py +2270 -196
- qnty/variables.pyi +6097 -0
- {qnty-0.0.2.dist-info → qnty-0.0.4.dist-info}/METADATA +1 -1
- qnty-0.0.4.dist-info/RECORD +19 -0
- qnty-0.0.2.dist-info/RECORD +0 -11
- {qnty-0.0.2.dist-info → qnty-0.0.4.dist-info}/WHEEL +0 -0
qnty/variable.py
CHANGED
@@ -10,7 +10,8 @@ from __future__ import annotations
|
|
10
10
|
|
11
11
|
from typing import Generic, Self, TypeVar
|
12
12
|
|
13
|
-
from .dimension import AREA, DIMENSIONLESS,
|
13
|
+
from .dimension import AREA, DIMENSIONLESS, FORCE, LENGTH, PRESSURE, VOLUME, DimensionSignature
|
14
|
+
from .dimension import ENERGY_HEAT_WORK as ENERGY
|
14
15
|
from .unit import UnitConstant, UnitDefinition, registry
|
15
16
|
from .units import DimensionlessUnits, LengthUnits, PressureUnits
|
16
17
|
|
File without changes
|
@@ -0,0 +1,58 @@
|
|
1
|
+
"""
|
2
|
+
Base Variable Module Definition
|
3
|
+
===============================
|
4
|
+
|
5
|
+
Provides abstract base class for variable modules and registration functionality.
|
6
|
+
"""
|
7
|
+
|
8
|
+
from abc import ABC, abstractmethod
|
9
|
+
from typing import Any
|
10
|
+
|
11
|
+
|
12
|
+
class VariableModule(ABC):
|
13
|
+
"""Abstract base class for variable modules."""
|
14
|
+
|
15
|
+
@abstractmethod
|
16
|
+
def get_variable_class(self) -> type[Any]:
|
17
|
+
"""Return the variable class for this module."""
|
18
|
+
pass
|
19
|
+
|
20
|
+
@abstractmethod
|
21
|
+
def get_setter_class(self) -> type[Any]:
|
22
|
+
"""Return the setter class for this module."""
|
23
|
+
pass
|
24
|
+
|
25
|
+
@abstractmethod
|
26
|
+
def get_expected_dimension(self) -> Any:
|
27
|
+
"""Return the expected dimension for this variable type."""
|
28
|
+
pass
|
29
|
+
|
30
|
+
def register_to_registry(self, variable_registry):
|
31
|
+
"""Register this variable module to the given registry."""
|
32
|
+
variable_registry.register_module(
|
33
|
+
self.get_expected_dimension(),
|
34
|
+
self.get_variable_class(),
|
35
|
+
self.get_setter_class()
|
36
|
+
)
|
37
|
+
|
38
|
+
|
39
|
+
class VariableRegistry:
|
40
|
+
"""Registry for variable modules."""
|
41
|
+
|
42
|
+
def __init__(self):
|
43
|
+
self._modules = {}
|
44
|
+
|
45
|
+
def register_module(self, dimension, variable_class, setter_class):
|
46
|
+
"""Register a variable module."""
|
47
|
+
self._modules[dimension] = {
|
48
|
+
'variable_class': variable_class,
|
49
|
+
'setter_class': setter_class
|
50
|
+
}
|
51
|
+
|
52
|
+
def get_variable_class(self, dimension):
|
53
|
+
"""Get variable class for a dimension."""
|
54
|
+
return self._modules.get(dimension, {}).get('variable_class')
|
55
|
+
|
56
|
+
def get_setter_class(self, dimension):
|
57
|
+
"""Get setter class for a dimension."""
|
58
|
+
return self._modules.get(dimension, {}).get('setter_class')
|
@@ -0,0 +1,68 @@
|
|
1
|
+
"""
|
2
|
+
Expression Variable Base Class
|
3
|
+
==============================
|
4
|
+
|
5
|
+
Base class that extends TypeSafeVariable with mathematical expression
|
6
|
+
and equation capabilities.
|
7
|
+
"""
|
8
|
+
|
9
|
+
from __future__ import annotations
|
10
|
+
|
11
|
+
from ..equation import Equation
|
12
|
+
from ..expression import Expression, wrap_operand
|
13
|
+
from ..variable import FastQuantity, TypeSafeVariable
|
14
|
+
|
15
|
+
|
16
|
+
class ExpressionVariable(TypeSafeVariable):
|
17
|
+
"""
|
18
|
+
TypeSafeVariable extended with expression and equation capabilities.
|
19
|
+
|
20
|
+
This adds mathematical operations that create expressions and equations,
|
21
|
+
keeping the base TypeSafeVariable free of these dependencies.
|
22
|
+
"""
|
23
|
+
|
24
|
+
def equals(self, expression: Expression | TypeSafeVariable | FastQuantity | int | float):
|
25
|
+
"""Create an equation: self = expression."""
|
26
|
+
# Wrap the expression in proper Expression type
|
27
|
+
rhs_expr = wrap_operand(expression)
|
28
|
+
return Equation(f"{self.name}_eq", self, rhs_expr)
|
29
|
+
|
30
|
+
def __add__(self, other: TypeSafeVariable | FastQuantity | int | float) -> Expression:
|
31
|
+
"""Add this variable to another operand, returning an Expression."""
|
32
|
+
return wrap_operand(self) + wrap_operand(other)
|
33
|
+
|
34
|
+
def __radd__(self, other: FastQuantity | int | float) -> Expression:
|
35
|
+
"""Reverse add for this variable."""
|
36
|
+
return wrap_operand(other) + wrap_operand(self)
|
37
|
+
|
38
|
+
def __sub__(self, other: TypeSafeVariable | FastQuantity | int | float) -> Expression:
|
39
|
+
"""Subtract another operand from this variable, returning an Expression."""
|
40
|
+
return wrap_operand(self) - wrap_operand(other)
|
41
|
+
|
42
|
+
def __rsub__(self, other: FastQuantity | int | float) -> Expression:
|
43
|
+
"""Reverse subtract for this variable."""
|
44
|
+
return wrap_operand(other) - wrap_operand(self)
|
45
|
+
|
46
|
+
def __mul__(self, other: TypeSafeVariable | FastQuantity | int | float) -> Expression:
|
47
|
+
"""Multiply this variable by another operand, returning an Expression."""
|
48
|
+
return wrap_operand(self) * wrap_operand(other)
|
49
|
+
|
50
|
+
def __rmul__(self, other: FastQuantity | int | float) -> Expression:
|
51
|
+
"""Reverse multiply for this variable."""
|
52
|
+
return wrap_operand(other) * wrap_operand(self)
|
53
|
+
|
54
|
+
def __truediv__(self, other: TypeSafeVariable | FastQuantity | int | float) -> Expression:
|
55
|
+
"""Divide this variable by another operand, returning an Expression."""
|
56
|
+
return wrap_operand(self) / wrap_operand(other)
|
57
|
+
|
58
|
+
def __rtruediv__(self, other: FastQuantity | int | float) -> Expression:
|
59
|
+
"""Reverse divide for this variable."""
|
60
|
+
return wrap_operand(other) / wrap_operand(self)
|
61
|
+
|
62
|
+
def __pow__(self, other: TypeSafeVariable | FastQuantity | int | float) -> Expression:
|
63
|
+
"""Raise this variable to a power, returning an Expression."""
|
64
|
+
return wrap_operand(self) ** wrap_operand(other)
|
65
|
+
|
66
|
+
def __rpow__(self, other: FastQuantity | int | float) -> Expression:
|
67
|
+
"""Reverse power for this variable."""
|
68
|
+
return wrap_operand(other) ** wrap_operand(self)
|
@@ -0,0 +1,92 @@
|
|
1
|
+
"""
|
2
|
+
Typed Variable Base Class
|
3
|
+
=========================
|
4
|
+
|
5
|
+
Base class that provides common constructor logic for all typed variables,
|
6
|
+
handling both the original syntax and the new value/unit/name syntax.
|
7
|
+
"""
|
8
|
+
|
9
|
+
from ..dimension import DimensionSignature
|
10
|
+
from ..variable import TypeSafeSetter
|
11
|
+
from .expression_variable import ExpressionVariable
|
12
|
+
|
13
|
+
|
14
|
+
class TypedVariable(ExpressionVariable):
|
15
|
+
"""
|
16
|
+
Base class for typed variables with common constructor logic.
|
17
|
+
|
18
|
+
Subclasses need to define:
|
19
|
+
- _setter_class: The setter class to use
|
20
|
+
- _expected_dimension: The expected dimension
|
21
|
+
- _default_unit_property: The default unit property name for fallback
|
22
|
+
"""
|
23
|
+
|
24
|
+
_setter_class: type[TypeSafeSetter] | None = None
|
25
|
+
_expected_dimension: DimensionSignature | None = None
|
26
|
+
_default_unit_property: str | None = None
|
27
|
+
|
28
|
+
def __init__(self, *args, is_known: bool = True):
|
29
|
+
"""
|
30
|
+
Flexible constructor supporting multiple syntaxes.
|
31
|
+
|
32
|
+
Single argument: TypedVariable("name")
|
33
|
+
Three arguments: TypedVariable(value, "unit", "name")
|
34
|
+
Two arguments (Dimensionless only): TypedVariable(value, "name")
|
35
|
+
"""
|
36
|
+
if self._setter_class is None or self._expected_dimension is None:
|
37
|
+
raise NotImplementedError("Subclass must define _setter_class and _expected_dimension")
|
38
|
+
|
39
|
+
# Handle different argument patterns
|
40
|
+
if len(args) == 1:
|
41
|
+
# Original syntax: Variable("name")
|
42
|
+
super().__init__(args[0], self._expected_dimension, is_known=is_known)
|
43
|
+
|
44
|
+
elif len(args) == 2 and self.__class__.__name__ == 'Dimensionless':
|
45
|
+
# Special case for Dimensionless: (value, "name")
|
46
|
+
value, name = args
|
47
|
+
super().__init__(name, self._expected_dimension, is_known=is_known)
|
48
|
+
setter = self._setter_class(self, value)
|
49
|
+
# For DimensionlessSetter, use the dimensionless property
|
50
|
+
# Type ignore since we know DimensionlessSetter has this property
|
51
|
+
getattr(setter, 'dimensionless', None) # type: ignore
|
52
|
+
|
53
|
+
elif len(args) == 3:
|
54
|
+
# New syntax: Variable(value, "unit", "name")
|
55
|
+
# But Dimensionless doesn't support this pattern
|
56
|
+
if self.__class__.__name__ == 'Dimensionless':
|
57
|
+
raise ValueError(f"{self.__class__.__name__} expects either 1 argument (name) or 2 arguments (value, name), got {len(args)}")
|
58
|
+
|
59
|
+
value, unit, name = args
|
60
|
+
super().__init__(name, self._expected_dimension, is_known=is_known)
|
61
|
+
|
62
|
+
# Auto-set the value with the specified unit
|
63
|
+
setter = self._setter_class(self, value)
|
64
|
+
|
65
|
+
# Handle special unit aliases
|
66
|
+
if unit == "in": # Handle Python reserved word
|
67
|
+
unit = "inchs" # Match the actual property name
|
68
|
+
elif unit == "inches": # Handle common plural form
|
69
|
+
unit = "inchs" # Match the actual property name
|
70
|
+
|
71
|
+
# Try to find the unit property on the setter
|
72
|
+
if hasattr(setter, unit):
|
73
|
+
getattr(setter, unit)
|
74
|
+
elif hasattr(setter, unit + 's'): # Handle singular/plural
|
75
|
+
getattr(setter, unit + 's')
|
76
|
+
elif self._default_unit_property and hasattr(setter, self._default_unit_property):
|
77
|
+
# Fall back to default unit
|
78
|
+
getattr(setter, self._default_unit_property)
|
79
|
+
else:
|
80
|
+
# Last resort - try to find any valid unit property
|
81
|
+
# This helps with forward compatibility
|
82
|
+
unit_properties = [attr for attr in dir(setter)
|
83
|
+
if not attr.startswith('_') and attr != 'value' and attr != 'variable']
|
84
|
+
if unit_properties:
|
85
|
+
getattr(setter, unit_properties[0])
|
86
|
+
|
87
|
+
else:
|
88
|
+
# More specific error messages matching test expectations
|
89
|
+
if self.__class__.__name__ == 'Dimensionless':
|
90
|
+
raise ValueError(f"{self.__class__.__name__} expects either 1 argument (name) or 2 arguments (value, name), got {len(args)}")
|
91
|
+
else:
|
92
|
+
raise ValueError(f"{self.__class__.__name__} expects either 1 argument (name) or 3 arguments (value, unit, name), got {len(args)}")
|