qnty 0.0.6__tar.gz → 0.0.8__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.
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.3
2
2
  Name: qnty
3
- Version: 0.0.6
3
+ Version: 0.0.8
4
4
  Summary: High-performance unit system library for Python with dimensional safety and fast unit conversions
5
5
  License: Apache-2.0
6
6
  Keywords: units,dimensional analysis,engineering,physics,quantities,measurements
@@ -1,6 +1,6 @@
1
1
  [project]
2
2
  name = "qnty"
3
- version = "0.0.6"
3
+ version = "0.0.8"
4
4
  description = "High-performance unit system library for Python with dimensional safety and fast unit conversions"
5
5
  readme = "README.md"
6
6
  license = { text = "Apache-2.0" }
@@ -28,7 +28,7 @@ class DimensionSignature:
28
28
  """Immutable dimension signature for zero-cost dimensional analysis."""
29
29
 
30
30
  # Store as bit pattern for ultra-fast comparison
31
- _signature: int = 1
31
+ _signature: int | float = 1
32
32
 
33
33
  @classmethod
34
34
  def create(cls, length=0, mass=0, time=0, current=0, temp=0, amount=0, luminosity=0):
@@ -55,7 +55,7 @@ class DimensionSignature:
55
55
  return DimensionSignature(self._signature * other._signature)
56
56
 
57
57
  def __truediv__(self, other):
58
- return DimensionSignature(self._signature // other._signature)
58
+ return DimensionSignature(self._signature / other._signature)
59
59
 
60
60
  def __pow__(self, power):
61
61
  return DimensionSignature(self._signature ** power)
@@ -117,7 +117,88 @@ class Equation:
117
117
  except Exception:
118
118
  return False
119
119
 
120
+ def _discover_variables_from_scope(self) -> dict[str, TypeSafeVariable]:
121
+ """Automatically discover variables from the calling scope."""
122
+ import inspect
123
+
124
+ # Get the frame that called this method (skip through __str__ calls)
125
+ frame = inspect.currentframe()
126
+ try:
127
+ # Skip frames until we find one outside the equation system
128
+ while frame and (
129
+ frame.f_code.co_filename.endswith(('equation.py', 'expression.py')) or
130
+ frame.f_code.co_name in ['__str__', '__repr__']
131
+ ):
132
+ frame = frame.f_back
133
+
134
+ if not frame:
135
+ return {}
136
+
137
+ # Combine local and global variables
138
+ all_vars = {**frame.f_globals, **frame.f_locals}
139
+
140
+ # Find TypeSafeVariable objects that match our required variables
141
+ required_vars = self.variables
142
+ discovered = {}
143
+
144
+ for var_name in required_vars:
145
+ for name, obj in all_vars.items():
146
+ if hasattr(obj, 'symbol') and obj.symbol == var_name:
147
+ discovered[var_name] = obj
148
+ break
149
+ elif hasattr(obj, 'name') and obj.name == var_name:
150
+ discovered[var_name] = obj
151
+ break
152
+
153
+ return discovered
154
+
155
+ finally:
156
+ del frame
157
+
158
+ def _can_auto_solve(self) -> tuple[bool, str, dict[str, TypeSafeVariable]]:
159
+ """Check if equation can be auto-solved from scope."""
160
+ try:
161
+ discovered = self._discover_variables_from_scope()
162
+
163
+ # Check if this is a simple assignment equation (one unknown)
164
+ unknowns = []
165
+ knowns = []
166
+
167
+ for var_name in self.variables:
168
+ if var_name in discovered:
169
+ var = discovered[var_name]
170
+ if hasattr(var, 'is_known') and not var.is_known:
171
+ unknowns.append(var_name)
172
+ elif hasattr(var, 'quantity') and var.quantity is not None:
173
+ knowns.append(var_name)
174
+ else:
175
+ unknowns.append(var_name) # Assume unknown if no quantity
176
+ else:
177
+ return False, "", {} # Missing variable
178
+
179
+ # Can only auto-solve if there's exactly one unknown
180
+ if len(unknowns) == 1:
181
+ return True, unknowns[0], discovered
182
+
183
+ return False, "", {}
184
+
185
+ except Exception:
186
+ return False, "", {}
187
+
188
+ def _try_auto_solve(self) -> bool:
189
+ """Try to automatically solve the equation if possible."""
190
+ try:
191
+ can_solve, target_var, variables = self._can_auto_solve()
192
+ if can_solve:
193
+ self.solve_for(target_var, variables)
194
+ return True
195
+ return False
196
+ except Exception:
197
+ return False
198
+
120
199
  def __str__(self) -> str:
200
+ # Try to auto-solve if possible before displaying
201
+ self._try_auto_solve()
121
202
  return f"{self.lhs} = {self.rhs}"
122
203
 
123
204
  def __repr__(self) -> str:
@@ -62,6 +62,80 @@ class Expression(ABC):
62
62
  def __str__(self) -> str:
63
63
  pass
64
64
 
65
+ def _discover_variables_from_scope(self) -> dict[str, 'TypeSafeVariable']:
66
+ """Automatically discover variables from the calling scope."""
67
+ import inspect
68
+
69
+ # Get the frame that called this method (skip through __str__ calls)
70
+ frame = inspect.currentframe()
71
+ try:
72
+ # Skip frames until we find one outside the expression system
73
+ while frame and (
74
+ frame.f_code.co_filename.endswith('expression.py') or
75
+ frame.f_code.co_name in ['__str__', '__repr__']
76
+ ):
77
+ frame = frame.f_back
78
+
79
+ if not frame:
80
+ return {}
81
+
82
+ # Combine local and global variables
83
+ all_vars = {**frame.f_globals, **frame.f_locals}
84
+
85
+ # Find TypeSafeVariable objects that match our required variables
86
+ required_vars = self.get_variables()
87
+ discovered = {}
88
+
89
+ for var_name in required_vars:
90
+ for name, obj in all_vars.items():
91
+ # Check if this is a TypeSafeVariable with matching symbol/name
92
+ if hasattr(obj, 'symbol') and obj.symbol == var_name:
93
+ discovered[var_name] = obj
94
+ break
95
+ elif hasattr(obj, 'name') and obj.name == var_name:
96
+ discovered[var_name] = obj
97
+ break
98
+ # Check if this is an Expression that can be evaluated to get the variable
99
+ elif hasattr(obj, 'get_variables') and name == var_name:
100
+ # This is an expression named after our variable - try to evaluate it
101
+ try:
102
+ if hasattr(obj, '_can_auto_evaluate'):
103
+ can_eval, expr_vars = obj._can_auto_evaluate()
104
+ if can_eval:
105
+ result = obj.evaluate(expr_vars)
106
+ # Create a temporary variable to hold the result
107
+ from .variables import Length # Import here to avoid circular import
108
+ temp_var = Length(result.value, result.unit.symbol, f"temp_{var_name}")
109
+ temp_var.symbol = var_name
110
+ discovered[var_name] = temp_var
111
+ break
112
+ except Exception:
113
+ pass
114
+
115
+ return discovered
116
+
117
+ finally:
118
+ del frame
119
+
120
+ def _can_auto_evaluate(self) -> tuple[bool, dict[str, 'TypeSafeVariable']]:
121
+ """Check if expression can be auto-evaluated from scope."""
122
+ try:
123
+ discovered = self._discover_variables_from_scope()
124
+ required_vars = self.get_variables()
125
+
126
+ # Check if all required variables are available and have values
127
+ for var_name in required_vars:
128
+ if var_name not in discovered:
129
+ return False, {}
130
+ var = discovered[var_name]
131
+ if not hasattr(var, 'quantity') or var.quantity is None:
132
+ return False, {}
133
+
134
+ return True, discovered
135
+
136
+ except Exception:
137
+ return False, {}
138
+
65
139
  def __add__(self, other: Union['Expression', 'TypeSafeVariable', 'FastQuantity', int, float]) -> 'Expression':
66
140
  return BinaryOperation('+', self, wrap_operand(other))
67
141
 
@@ -93,17 +167,17 @@ class Expression(ABC):
93
167
  return BinaryOperation('**', wrap_operand(other), self)
94
168
 
95
169
  # Comparison operators for conditional expressions
96
- def __lt__(self, other: Union['Expression', 'TypeSafeVariable', 'FastQuantity', int, float]) -> 'ComparisonExpression':
97
- return ComparisonExpression('<', self, self._wrap_operand(other))
170
+ def __lt__(self, other: Union['Expression', 'TypeSafeVariable', 'FastQuantity', int, float]) -> 'BinaryOperation':
171
+ return BinaryOperation('<', self, self._wrap_operand(other))
98
172
 
99
- def __le__(self, other: Union['Expression', 'TypeSafeVariable', 'FastQuantity', int, float]) -> 'ComparisonExpression':
100
- return ComparisonExpression('<=', self, self._wrap_operand(other))
173
+ def __le__(self, other: Union['Expression', 'TypeSafeVariable', 'FastQuantity', int, float]) -> 'BinaryOperation':
174
+ return BinaryOperation('<=', self, self._wrap_operand(other))
101
175
 
102
- def __gt__(self, other: Union['Expression', 'TypeSafeVariable', 'FastQuantity', int, float]) -> 'ComparisonExpression':
103
- return ComparisonExpression('>', self, self._wrap_operand(other))
176
+ def __gt__(self, other: Union['Expression', 'TypeSafeVariable', 'FastQuantity', int, float]) -> 'BinaryOperation':
177
+ return BinaryOperation('>', self, self._wrap_operand(other))
104
178
 
105
- def __ge__(self, other: Union['Expression', 'TypeSafeVariable', 'FastQuantity', int, float]) -> 'ComparisonExpression':
106
- return ComparisonExpression('>=', self, self._wrap_operand(other))
179
+ def __ge__(self, other: Union['Expression', 'TypeSafeVariable', 'FastQuantity', int, float]) -> 'BinaryOperation':
180
+ return BinaryOperation('>=', self, self._wrap_operand(other))
107
181
 
108
182
  @staticmethod
109
183
  def _wrap_operand(operand: Union['Expression', 'TypeSafeVariable', 'FastQuantity', int, float]) -> 'Expression':
@@ -167,6 +241,7 @@ class Constant(Expression):
167
241
  self.value = value
168
242
 
169
243
  def evaluate(self, variable_values: dict[str, 'TypeSafeVariable']) -> 'FastQuantity':
244
+ del variable_values # Suppress unused variable warning
170
245
  return self.value
171
246
 
172
247
  def get_variables(self) -> set[str]:
@@ -214,6 +289,30 @@ class BinaryOperation(Expression):
214
289
  return FastQuantity(result_value, left_val.unit)
215
290
  else:
216
291
  raise ValueError("Exponent must be dimensionless number")
292
+ elif self.operator in ['<', '<=', '>', '>=', '==', '!=']:
293
+ # Comparison operations - return dimensionless 1.0 or 0.0
294
+ # Convert to same units for comparison if possible
295
+ try:
296
+ if left_val._dimension_sig == right_val._dimension_sig and left_val.unit != right_val.unit:
297
+ right_val = right_val.to(left_val.unit)
298
+ except (ValueError, TypeError, AttributeError):
299
+ pass
300
+
301
+ result = False # Initialize result
302
+ if self.operator == '<':
303
+ result = left_val.value < right_val.value
304
+ elif self.operator == '<=':
305
+ result = left_val.value <= right_val.value
306
+ elif self.operator == '>':
307
+ result = left_val.value > right_val.value
308
+ elif self.operator == '>=':
309
+ result = left_val.value >= right_val.value
310
+ elif self.operator == '==':
311
+ result = abs(left_val.value - right_val.value) < 1e-10
312
+ elif self.operator == '!=':
313
+ result = abs(left_val.value - right_val.value) >= 1e-10
314
+
315
+ return FastQuantity(1.0 if result else 0.0, DimensionlessUnits.dimensionless)
217
316
  else:
218
317
  raise ValueError(f"Unknown operator: {self.operator}")
219
318
  except Exception as e:
@@ -241,8 +340,17 @@ class BinaryOperation(Expression):
241
340
  return BinaryOperation(self.operator, left_simplified, right_simplified)
242
341
 
243
342
  def __str__(self) -> str:
343
+ # Try to auto-evaluate if all variables are available
344
+ can_eval, variables = self._can_auto_evaluate()
345
+ if can_eval:
346
+ try:
347
+ result = self.evaluate(variables)
348
+ return str(result)
349
+ except Exception:
350
+ pass # Fall back to symbolic representation
351
+
244
352
  # Handle operator precedence for cleaner string representation
245
- precedence = {'+': 1, '-': 1, '*': 2, '/': 2, '**': 3}
353
+ precedence = {'+': 1, '-': 1, '*': 2, '/': 2, '**': 3, '<': 0, '<=': 0, '>': 0, '>=': 0, '==': 0, '!=': 0}
246
354
  left_str = str(self.left)
247
355
  right_str = str(self.right)
248
356
 
@@ -260,60 +368,13 @@ class BinaryOperation(Expression):
260
368
  # Need parentheses if:
261
369
  # - Right has lower precedence, OR
262
370
  # - Same precedence and current operator is left-associative (- or /)
263
- if (right_prec < curr_prec or
371
+ if (right_prec < curr_prec or
264
372
  (right_prec == curr_prec and self.operator in ['-', '/'])):
265
373
  right_str = f"({right_str})"
266
374
 
267
375
  return f"{left_str} {self.operator} {right_str}"
268
376
 
269
377
 
270
- class ComparisonExpression(Expression):
271
- """Comparison expression for conditional logic."""
272
-
273
- def __init__(self, operator: str, left: Expression, right: Expression):
274
- self.operator = operator
275
- self.left = left
276
- self.right = right
277
-
278
- def evaluate(self, variable_values: dict[str, 'TypeSafeVariable']) -> 'FastQuantity':
279
- """Evaluate comparison and return dimensionless result (1.0 for True, 0.0 for False)."""
280
-
281
- left_val = self.left.evaluate(variable_values)
282
- right_val = self.right.evaluate(variable_values)
283
-
284
- # Convert to same units for comparison if possible
285
- try:
286
- if left_val._dimension_sig == right_val._dimension_sig and left_val.unit != right_val.unit:
287
- right_val = right_val.to(left_val.unit)
288
- except (ValueError, TypeError, AttributeError):
289
- pass
290
-
291
- if self.operator == '<':
292
- result = left_val.value < right_val.value
293
- elif self.operator == '<=':
294
- result = left_val.value <= right_val.value
295
- elif self.operator == '>':
296
- result = left_val.value > right_val.value
297
- elif self.operator == '>=':
298
- result = left_val.value >= right_val.value
299
- elif self.operator == '==':
300
- result = abs(left_val.value - right_val.value) < 1e-10
301
- elif self.operator == '!=':
302
- result = abs(left_val.value - right_val.value) >= 1e-10
303
- else:
304
- raise ValueError(f"Unknown comparison operator: {self.operator}")
305
-
306
- return FastQuantity(1.0 if result else 0.0, DimensionlessUnits.dimensionless)
307
-
308
- def get_variables(self) -> set[str]:
309
- return self.left.get_variables() | self.right.get_variables()
310
-
311
- def simplify(self) -> Expression:
312
- return ComparisonExpression(self.operator, self.left.simplify(), self.right.simplify())
313
-
314
- def __str__(self) -> str:
315
- return f"({self.left} {self.operator} {self.right})"
316
-
317
378
 
318
379
  class UnaryFunction(Expression):
319
380
  """Unary mathematical function expression."""
@@ -453,7 +514,7 @@ def exp(expr: Union[Expression, 'TypeSafeVariable', 'FastQuantity', int, float])
453
514
  """Exponential function."""
454
515
  return UnaryFunction('exp', Expression._wrap_operand(expr))
455
516
 
456
- def cond_expr(condition: Union[Expression, 'ComparisonExpression'],
517
+ def cond_expr(condition: Union[Expression, 'BinaryOperation'],
457
518
  true_expr: Union[Expression, 'TypeSafeVariable', 'FastQuantity', int, float],
458
519
  false_expr: Union[Expression, 'TypeSafeVariable', 'FastQuantity', int, float]) -> ConditionalExpression:
459
520
  """Conditional expression: if condition then true_expr else false_expr."""
@@ -64,8 +64,8 @@ class HighPerformanceRegistry:
64
64
  def __init__(self):
65
65
  self.units: dict[str, UnitDefinition] = {}
66
66
  self.conversion_table: dict[tuple[str, str], float] = {} # (from_unit, to_unit) -> factor
67
- self.dimensional_groups: dict[int, list[UnitDefinition]] = {}
68
- self._dimension_cache: dict[int, UnitConstant] = {} # Cache for common dimension mappings
67
+ self.dimensional_groups: dict[int | float, list[UnitDefinition]] = {}
68
+ self._dimension_cache: dict[int | float, UnitConstant] = {} # Cache for common dimension mappings
69
69
  self._finalized = False
70
70
  self.base_units: dict[str, UnitDefinition] = {} # Track base units for prefix generation
71
71
  self.prefixable_units: set[str] = set() # Track which units can have prefixes
@@ -22,6 +22,9 @@ from .dimension import (
22
22
  CONCENTRATION,
23
23
  DIMENSIONLESS,
24
24
  DYNAMIC_FLUIDITY,
25
+ ELECTRICAL_CONDUCTANCE,
26
+ ELECTRICAL_PERMITTIVITY,
27
+ ELECTRICAL_RESISTIVITY,
25
28
  ELECTRIC_CAPACITANCE,
26
29
  ELECTRIC_CHARGE,
27
30
  ELECTRIC_CURRENT_INTENSITY,
@@ -30,9 +33,6 @@ from .dimension import (
30
33
  ELECTRIC_INDUCTANCE,
31
34
  ELECTRIC_POTENTIAL,
32
35
  ELECTRIC_RESISTANCE,
33
- ELECTRICAL_CONDUCTANCE,
34
- ELECTRICAL_PERMITTIVITY,
35
- ELECTRICAL_RESISTIVITY,
36
36
  ENERGY_FLUX,
37
37
  ENERGY_HEAT_WORK,
38
38
  ENERGY_PER_UNIT_AREA,
@@ -65,14 +65,14 @@ from .dimension import (
65
65
  MASS_FLUX,
66
66
  MASS_TRANSFER_COEFFICIENT,
67
67
  MOLALITY_OF_SOLUTE_I,
68
+ MOLARITY_OF_I,
68
69
  MOLAR_CONCENTRATION_BY_MASS,
69
70
  MOLAR_FLOW_RATE,
70
71
  MOLAR_FLUX,
71
72
  MOLAR_HEAT_CAPACITY,
72
- MOLARITY_OF_I,
73
- MOMENT_OF_INERTIA,
74
73
  MOMENTUM_FLOW_RATE,
75
74
  MOMENTUM_FLUX,
75
+ MOMENT_OF_INERTIA,
76
76
  NORMALITY_OF_SOLUTION,
77
77
  PARTICLE_DENSITY,
78
78
  PERMEABILITY,
@@ -109,7 +109,7 @@ from .dimension import (
109
109
  VOLUMETRIC_FLOW_RATE,
110
110
  VOLUMETRIC_FLUX,
111
111
  VOLUMETRIC_MASS_FLOW_RATE,
112
- WAVENUMBER,
112
+ WAVENUMBER
113
113
  )
114
114
 
115
115
  # Comprehensive unit definitions organized by dimensional signature
@@ -7896,8 +7896,8 @@ UNIT_DEFINITIONS = {
7896
7896
 
7897
7897
  def create_unit_class(class_name: str, dimension_data: dict) -> type:
7898
7898
  """Dynamically create a unit class with all unit constants as attributes."""
7899
- from .prefixes import get_prefix_by_name
7900
7899
  from .unit import UnitConstant, UnitDefinition
7900
+ from .prefixes import get_prefix_by_name
7901
7901
 
7902
7902
  # Create a new class dynamically
7903
7903
  unit_class = type(class_name, (), {})
@@ -7950,8 +7950,8 @@ def create_unit_class(class_name: str, dimension_data: dict) -> type:
7950
7950
 
7951
7951
  def register_all_units(registry):
7952
7952
  """Register all unit definitions to the given registry with prefix support."""
7953
- from .prefixes import PREFIXABLE_UNITS
7954
7953
  from .unit import UnitDefinition
7954
+ from .prefixes import get_prefix_by_name, StandardPrefixes, PREFIXABLE_UNITS
7955
7955
 
7956
7956
  # First pass: register base units with prefixes where applicable
7957
7957
  for dimension_data in UNIT_DEFINITIONS.values():
@@ -115,7 +115,7 @@ class FastQuantity:
115
115
  return FastQuantity(self.value / other, self.unit)
116
116
 
117
117
  # Fast dimensional analysis using cached signatures
118
- result_dimension_sig = self._dimension_sig // other._dimension_sig
118
+ result_dimension_sig = self._dimension_sig / other._dimension_sig
119
119
 
120
120
  # Use cached SI factors for conversion
121
121
  self_si_value = self.value * self._si_factor
@@ -128,7 +128,7 @@ class FastQuantity:
128
128
 
129
129
  return FastQuantity(result_value, result_unit)
130
130
 
131
- def _find_result_unit_fast(self, result_dimension_sig: int,
131
+ def _find_result_unit_fast(self, result_dimension_sig: int | float,
132
132
  left_qty: FastQuantity, right_qty: FastQuantity) -> UnitConstant:
133
133
  """Ultra-fast unit finding using cached dimension signatures."""
134
134
 
@@ -257,6 +257,43 @@ class TypeSafeVariable(Generic[DimensionType]):
257
257
  self.is_known = True
258
258
  return self
259
259
 
260
+ def update(self, value=None, unit=None, quantity=None, is_known=None):
261
+ """Update variable properties flexibly."""
262
+ if quantity is not None:
263
+ self.quantity = quantity
264
+ elif value is not None:
265
+ # Create setter and call the appropriate unit property
266
+ setter = self.set(value)
267
+ if unit is not None:
268
+ # Try to find the unit property on the setter
269
+ if hasattr(setter, unit):
270
+ getattr(setter, unit)
271
+ elif hasattr(setter, unit + 's'): # Handle singular/plural
272
+ getattr(setter, unit + 's')
273
+ elif unit.endswith('s') and hasattr(setter, unit[:-1]): # Handle plural to singular
274
+ getattr(setter, unit[:-1])
275
+ else:
276
+ raise ValueError(f"Unit '{unit}' not found for {self.__class__.__name__}")
277
+ else:
278
+ # If no unit specified, we can't automatically choose a unit
279
+ # The caller should specify either a unit or a quantity
280
+ raise ValueError("Must specify either 'unit' with 'value' or provide 'quantity' directly")
281
+ if is_known is not None:
282
+ self.is_known = is_known
283
+ return self # For method chaining
284
+
285
+ def mark_known(self, quantity=None):
286
+ """Mark variable as known, optionally updating its value."""
287
+ self.is_known = True
288
+ if quantity is not None:
289
+ self.quantity = quantity
290
+ return self # For method chaining
291
+
292
+ def mark_unknown(self):
293
+ """Mark variable as unknown."""
294
+ self.is_known = False
295
+ return self # For method chaining
296
+
260
297
  def __str__(self):
261
298
  return f"{self.name}: {self.quantity}" if self.quantity else f"{self.name}: unset"
262
299
 
@@ -66,3 +66,41 @@ class ExpressionVariable(TypeSafeVariable):
66
66
  def __rpow__(self, other: FastQuantity | int | float) -> Expression:
67
67
  """Reverse power for this variable."""
68
68
  return wrap_operand(other) ** wrap_operand(self)
69
+
70
+ # Comparison methods
71
+ def lt(self, other: TypeSafeVariable | FastQuantity | int | float) -> Expression:
72
+ """Less than comparison (<)."""
73
+ from ..expression import BinaryOperation
74
+ return BinaryOperation('<', wrap_operand(self), wrap_operand(other))
75
+
76
+ def leq(self, other: TypeSafeVariable | FastQuantity | int | float) -> Expression:
77
+ """Less than or equal comparison (<=)."""
78
+ from ..expression import BinaryOperation
79
+ return BinaryOperation('<=', wrap_operand(self), wrap_operand(other))
80
+
81
+ def geq(self, other: TypeSafeVariable | FastQuantity | int | float) -> Expression:
82
+ """Greater than or equal comparison (>=)."""
83
+ from ..expression import BinaryOperation
84
+ return BinaryOperation('>=', wrap_operand(self), wrap_operand(other))
85
+
86
+ def gt(self, other: TypeSafeVariable | FastQuantity | int | float) -> Expression:
87
+ """Greater than comparison (>)."""
88
+ from ..expression import BinaryOperation
89
+ return BinaryOperation('>', wrap_operand(self), wrap_operand(other))
90
+
91
+ # Python comparison operators
92
+ def __lt__(self, other: TypeSafeVariable | FastQuantity | int | float) -> Expression:
93
+ """Less than comparison (<) operator."""
94
+ return self.lt(other)
95
+
96
+ def __le__(self, other: TypeSafeVariable | FastQuantity | int | float) -> Expression:
97
+ """Less than or equal comparison (<=) operator."""
98
+ return self.leq(other)
99
+
100
+ def __gt__(self, other: TypeSafeVariable | FastQuantity | int | float) -> Expression:
101
+ """Greater than comparison (>) operator."""
102
+ return self.gt(other)
103
+
104
+ def __ge__(self, other: TypeSafeVariable | FastQuantity | int | float) -> Expression:
105
+ """Greater than or equal comparison (>=) operator."""
106
+ return self.geq(other)
@@ -9,7 +9,6 @@ Auto-generated from unit_data.json and dimension_mapping.json.
9
9
 
10
10
  from typing import Any
11
11
 
12
- from . import units
13
12
  from .dimension import (
14
13
  ABSORBED_DOSE,
15
14
  ACCELERATION,
@@ -25,6 +24,9 @@ from .dimension import (
25
24
  CONCENTRATION,
26
25
  DIMENSIONLESS,
27
26
  DYNAMIC_FLUIDITY,
27
+ ELECTRICAL_CONDUCTANCE,
28
+ ELECTRICAL_PERMITTIVITY,
29
+ ELECTRICAL_RESISTIVITY,
28
30
  ELECTRIC_CAPACITANCE,
29
31
  ELECTRIC_CHARGE,
30
32
  ELECTRIC_CURRENT_INTENSITY,
@@ -33,9 +35,6 @@ from .dimension import (
33
35
  ELECTRIC_INDUCTANCE,
34
36
  ELECTRIC_POTENTIAL,
35
37
  ELECTRIC_RESISTANCE,
36
- ELECTRICAL_CONDUCTANCE,
37
- ELECTRICAL_PERMITTIVITY,
38
- ELECTRICAL_RESISTIVITY,
39
38
  ENERGY_FLUX,
40
39
  ENERGY_HEAT_WORK,
41
40
  ENERGY_PER_UNIT_AREA,
@@ -69,15 +68,15 @@ from .dimension import (
69
68
  MASS_FRACTION_OF_I,
70
69
  MASS_TRANSFER_COEFFICIENT,
71
70
  MOLALITY_OF_SOLUTE_I,
71
+ MOLARITY_OF_I,
72
72
  MOLAR_CONCENTRATION_BY_MASS,
73
73
  MOLAR_FLOW_RATE,
74
74
  MOLAR_FLUX,
75
75
  MOLAR_HEAT_CAPACITY,
76
- MOLARITY_OF_I,
77
76
  MOLE_FRACTION_OF_I,
78
- MOMENT_OF_INERTIA,
79
77
  MOMENTUM_FLOW_RATE,
80
78
  MOMENTUM_FLUX,
79
+ MOMENT_OF_INERTIA,
81
80
  NORMALITY_OF_SOLUTION,
82
81
  PARTICLE_DENSITY,
83
82
  PERCENT,
@@ -111,14 +110,16 @@ from .dimension import (
111
110
  VISCOSITY_DYNAMIC,
112
111
  VISCOSITY_KINEMATIC,
113
112
  VOLUME,
114
- VOLUME_FRACTION_OF_I,
115
113
  VOLUMETRIC_CALORIFIC_HEATING_VALUE,
116
114
  VOLUMETRIC_COEFFICIENT_OF_EXPANSION,
117
115
  VOLUMETRIC_FLOW_RATE,
118
116
  VOLUMETRIC_FLUX,
119
117
  VOLUMETRIC_MASS_FLOW_RATE,
118
+ VOLUME_FRACTION_OF_I,
120
119
  WAVENUMBER,
121
120
  )
121
+ from . import units
122
+ from .unit import UnitConstant, UnitDefinition
122
123
  from .variable import FastQuantity, TypeSafeSetter
123
124
  from .variable_types.typed_variable import TypedVariable
124
125
 
File without changes
File without changes
File without changes
File without changes
File without changes