qnty 0.1.4__py3-none-any.whl → 0.1.5__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.
@@ -16,8 +16,24 @@ ConditionalOperand = Expression | BinaryOperation
16
16
  def _create_unary_function(name: str, docstring: str):
17
17
  """Factory function for creating unary mathematical functions."""
18
18
 
19
- def func(expr: ExpressionOperand) -> UnaryFunction:
20
- return UnaryFunction(name, wrap_operand(expr))
19
+ def func(expr: ExpressionOperand):
20
+ from .nodes import VariableReference
21
+
22
+ wrapped_expr = wrap_operand(expr)
23
+
24
+ # For known quantities (FieldQnty with known values), evaluate immediately
25
+ if hasattr(expr, 'quantity') and expr.quantity is not None:
26
+ try:
27
+ unary_func = UnaryFunction(name, wrapped_expr)
28
+ # Use an empty variable dict since we have the quantity directly
29
+ result = unary_func.evaluate({})
30
+ return result
31
+ except (ValueError, TypeError, AttributeError):
32
+ # Fall back to expression if evaluation fails
33
+ pass
34
+
35
+ # For unknown variables or expressions, return the UnaryFunction
36
+ return UnaryFunction(name, wrapped_expr)
21
37
 
22
38
  func.__name__ = name
23
39
  func.__doc__ = docstring
qnty/expressions/nodes.py CHANGED
@@ -514,14 +514,14 @@ class UnaryFunction(Expression):
514
514
 
515
515
  # Function dispatch table for better performance and maintainability
516
516
  functions = {
517
- "sin": lambda x: Quantity(math.sin(x.value), DimensionlessUnits.dimensionless),
518
- "cos": lambda x: Quantity(math.cos(x.value), DimensionlessUnits.dimensionless),
519
- "tan": lambda x: Quantity(math.tan(x.value), DimensionlessUnits.dimensionless),
517
+ "sin": lambda x: math.sin(self._to_radians_if_angle(x)),
518
+ "cos": lambda x: math.cos(self._to_radians_if_angle(x)),
519
+ "tan": lambda x: math.tan(self._to_radians_if_angle(x)),
520
520
  "sqrt": lambda x: Quantity(math.sqrt(x.value), x.unit),
521
521
  "abs": lambda x: Quantity(abs(x.value), x.unit),
522
- "ln": lambda x: Quantity(math.log(x.value), DimensionlessUnits.dimensionless),
523
- "log10": lambda x: Quantity(math.log10(x.value), DimensionlessUnits.dimensionless),
524
- "exp": lambda x: Quantity(math.exp(x.value), DimensionlessUnits.dimensionless),
522
+ "ln": lambda x: math.log(x.value),
523
+ "log10": lambda x: math.log10(x.value),
524
+ "exp": lambda x: math.exp(x.value),
525
525
  }
526
526
 
527
527
  func = functions.get(self.function_name)
@@ -530,6 +530,35 @@ class UnaryFunction(Expression):
530
530
  else:
531
531
  raise ValueError(f"Unknown function: {self.function_name}")
532
532
 
533
+ def _to_radians_if_angle(self, quantity: "Quantity") -> float:
534
+ """Convert angle quantities to radians for trigonometric functions."""
535
+ from ..dimensions import field_dims
536
+
537
+ # Check if this is an angle dimension by comparing dimension signature
538
+ # Need to handle the case where angle dimensions might not exactly match due to implementation details
539
+ try:
540
+ # Import angle plane dimension for comparison
541
+ angle_plane_dim = field_dims.ANGLE_PLANE
542
+
543
+ # If this looks like an angle (has angle dimension or unit name suggests it)
544
+ if (hasattr(quantity, '_dimension_sig') and quantity._dimension_sig == angle_plane_dim) or \
545
+ (hasattr(quantity, 'unit') and hasattr(quantity.unit, 'name') and
546
+ any(angle_word in str(quantity.unit.name).lower() for angle_word in ['degree', 'radian', 'grad', 'gon'])):
547
+
548
+ # Import the radian unit for conversion
549
+ from ..units.field_units import AnglePlaneUnits
550
+
551
+ # Convert to radians and return the numeric value
552
+ radian_quantity = quantity.to(AnglePlaneUnits.radian.definition)
553
+ return radian_quantity.value
554
+ else:
555
+ # Non-angle quantities: return raw value (backward compatibility)
556
+ return quantity.value
557
+ except (ImportError, AttributeError, ValueError):
558
+ # If anything goes wrong with angle detection/conversion, fall back to raw value
559
+ return quantity.value
560
+
561
+
533
562
  def get_variables(self) -> set[str]:
534
563
  return self.operand.get_variables()
535
564
 
@@ -546,6 +575,15 @@ class UnaryFunction(Expression):
546
575
  return UnaryFunction(self.function_name, simplified_operand)
547
576
 
548
577
  def __str__(self) -> str:
578
+ # Try auto-evaluation first if possible
579
+ can_eval, variables = self._can_auto_evaluate()
580
+ if can_eval and variables:
581
+ try:
582
+ result = self.evaluate(variables)
583
+ return str(result)
584
+ except (ValueError, TypeError, AttributeError):
585
+ # Fall back to symbolic representation
586
+ pass
549
587
  return ExpressionFormatter.format_unary_function(self) # type: ignore[arg-type]
550
588
 
551
589
 
@@ -186,6 +186,8 @@ class ConfigurableVariable:
186
186
  return self._variable._arithmetic_mode
187
187
  # Otherwise default to 'expression'
188
188
  return 'expression'
189
+
190
+
189
191
  return getattr(self._variable, name)
190
192
 
191
193
  # Delegate arithmetic operations to the wrapped variable
@@ -233,10 +235,10 @@ class ConfigurableVariable:
233
235
  def __ge__(self, other):
234
236
  return self._variable.__ge__(other)
235
237
 
236
- def __eq__(self, other):
238
+ def __eq__(self, other): # type: ignore[override]
237
239
  return self._variable.__eq__(other)
238
240
 
239
- def __ne__(self, other):
241
+ def __ne__(self, other): # type: ignore[override]
240
242
  return self._variable.__ne__(other)
241
243
 
242
244
  def __setattr__(self, name, value):
@@ -257,6 +259,30 @@ class ConfigurableVariable:
257
259
  else:
258
260
  return original_setter
259
261
 
262
+ def update(self, value=None, unit=None, quantity=None, is_known=None):
263
+ """Override update method to track configuration changes."""
264
+ result = self._variable.update(value, unit, quantity, is_known)
265
+ if self._proxy and self._original_symbol:
266
+ # Track this configuration change
267
+ self._proxy.track_configuration(self._original_symbol, self._variable.quantity, self._variable.is_known)
268
+ return result
269
+
270
+ def mark_known(self):
271
+ """Override mark_known to track configuration changes."""
272
+ result = self._variable.mark_known()
273
+ if self._proxy and self._original_symbol:
274
+ # Track this configuration change
275
+ self._proxy.track_configuration(self._original_symbol, self._variable.quantity, self._variable.is_known)
276
+ return result
277
+
278
+ def mark_unknown(self):
279
+ """Override mark_unknown to track configuration changes."""
280
+ result = self._variable.mark_unknown()
281
+ if self._proxy and self._original_symbol:
282
+ # Track this configuration change
283
+ self._proxy.track_configuration(self._original_symbol, self._variable.quantity, self._variable.is_known)
284
+ return result
285
+
260
286
 
261
287
  class TrackingSetterWrapper:
262
288
  """
@@ -307,30 +333,6 @@ class TrackingSetterWrapper:
307
333
  )
308
334
  return result
309
335
 
310
- def update(self, value=None, unit=None, quantity=None, is_known=None):
311
- """Override update method to track configuration changes."""
312
- result = self._variable.update(value, unit, quantity, is_known)
313
- if self._proxy and self._original_symbol:
314
- # Track this configuration change
315
- self._proxy.track_configuration(self._original_symbol, self._variable.quantity, self._variable.is_known)
316
- return result
317
-
318
- def mark_known(self):
319
- """Override mark_known to track configuration changes."""
320
- result = self._variable.mark_known()
321
- if self._proxy and self._original_symbol:
322
- # Track this configuration change
323
- self._proxy.track_configuration(self._original_symbol, self._variable.quantity, self._variable.is_known)
324
- return result
325
-
326
- def mark_unknown(self):
327
- """Override mark_unknown to track configuration changes."""
328
- result = self._variable.mark_unknown()
329
- if self._proxy and self._original_symbol:
330
- # Track this configuration change
331
- self._proxy.track_configuration(self._original_symbol, self._variable.quantity, self._variable.is_known)
332
- return result
333
-
334
336
 
335
337
  class DelayedVariableReference(ArithmeticOperationsMixin):
336
338
  """
qnty/units/field_units.py CHANGED
@@ -248,7 +248,7 @@ class AnglePlaneUnits:
248
248
  name="degree",
249
249
  symbol="${ }^{\\circ}$",
250
250
  dimension=dim.ANGLE_PLANE,
251
- si_factor=0.0174533,
251
+ si_factor=0.017453292519943295,
252
252
  si_offset=0.0,
253
253
  ))
254
254
 
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.3
2
2
  Name: qnty
3
- Version: 0.1.4
3
+ Version: 0.1.5
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
@@ -13,15 +13,15 @@ qnty/equations/equation.py,sha256=EPw1mKTMriI94uKCqSWTPvQfcZTBLPhX-D4nDZI9vJg,10
13
13
  qnty/equations/system.py,sha256=vMoD1iTUrAHnVFVvCUKeyNfSBfMiqpwQbfDx46kN9N8,5155
14
14
  qnty/expressions/__init__.py,sha256=DA2s7DBhVCmdUgsYSTJWObsp2DbbpFn492yr1nUTg2g,930
15
15
  qnty/expressions/formatter.py,sha256=yLGLwLYjhBvVi2Q6rfkg8pbyH0-a1Ko0AYLsqJTJf50,7806
16
- qnty/expressions/functions.py,sha256=ek43udfUDpThKo38rVPBYPvKfZNc9Bbs8RuL-CvQc_A,2729
17
- qnty/expressions/nodes.py,sha256=Q6DgmhP7MVUkdsUpzzp7_yjV8hegd0AwETvd4bo8nWc,29362
16
+ qnty/expressions/functions.py,sha256=8IX-6eEhWYWr4yNjCZ4hcOZwcK1G-VcgTRddKkAsVUQ,3427
17
+ qnty/expressions/nodes.py,sha256=2kGn7BJH0ZAxM0fDNl62Mll8jgfcRtnbhf58lScj9rk,31134
18
18
  qnty/expressions/types.py,sha256=eoM-IqY-k-IypRHAlRwjEtMmB6DiwX7YGot8t_vGw3o,1729
19
19
  qnty/extensions/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
20
20
  qnty/extensions/integration/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
21
21
  qnty/extensions/plotting/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
22
22
  qnty/extensions/reporting/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
23
23
  qnty/problems/__init__.py,sha256=g7zuml2IecoSwgzX6r1zZ5SlmBKFc8qqTR_cao037pc,4808
24
- qnty/problems/composition.py,sha256=HI5ffsF14IXRuqjM0z_O0kkpme9fPnJVdz6m4rDCJsM,44916
24
+ qnty/problems/composition.py,sha256=2i5swVTRvB-aqnQHyPXwBXJnhjKt8isgm4j5CsExkYs,44986
25
25
  qnty/problems/problem.py,sha256=xnkHsI9OcY3HJ0UxtMnMQrS6n7accl4d-5fSJQ6ITPo,31721
26
26
  qnty/problems/rules.py,sha256=NwIStAa8bocVtvzAsnPmRdC_0ENTJWyXLOoYBnkvpPA,5176
27
27
  qnty/problems/solving.py,sha256=LTI8F9ujDiSqXE9Aiz8sOgaGJNX9p7oaR5CQIZHpCY8,44315
@@ -42,7 +42,7 @@ qnty/solving/solvers/base.py,sha256=UgXRhnx9m331Hn2P3U-0qTfSQIkfOhEw_MfqcLhxxBM,
42
42
  qnty/solving/solvers/iterative.py,sha256=dZw66VRz0ScnkPsJl2miKgH7VVcGJQw1zq-5wzU0CZU,7557
43
43
  qnty/solving/solvers/simultaneous.py,sha256=hLZ8878BqiI5NQd8eeRG5Sy9ztS43BBX4mk3BDMVs_4,21609
44
44
  qnty/units/__init__.py,sha256=WgH6t1obC5i2ioEykO8H3z_csoRL6fP6xjzXn2_EB80,27
45
- qnty/units/field_units.py,sha256=juW8qzt7UaL4lIMl5p_GVcfH6h6gQz7bFuOUOKRX7rY,283034
45
+ qnty/units/field_units.py,sha256=5c0TdvbXT5nCFIS017cm5uLbM8-NUT3SeIsRyHAEpac,283045
46
46
  qnty/units/field_units.pyi,sha256=1iW_yWF2PWQ8wZ1vSp2SbHk4A6eiG-Hfw-9VdSBf7s0,77949
47
47
  qnty/units/prefixes.py,sha256=tSD8CIPjFtCuwl2Og1a1pmqLoTvfeTljxMqPuHBC_dE,6667
48
48
  qnty/units/registry.py,sha256=bfnD4kWkaEnX0Vkb7Dxa1K-YGhtjMNQjevLpcMc7KCQ,6728
@@ -57,6 +57,6 @@ qnty/utils/logging.py,sha256=2H6_gSOQjxdK5024XTY3E1jGIQPE8WdalVhVBFw51OA,1143
57
57
  qnty/utils/protocols.py,sha256=c_Ya_epCm7qenAADRMZiwiQ0PdD-Z4T85b1z1YQNXAk,5247
58
58
  qnty/utils/scope_discovery.py,sha256=mQc-FHJ5-VNBzqQwiFofV-hqeF3GpLRaLlTjYDRnOqs,15184
59
59
  qnty/utils/unit_suggestions.py,sha256=V_eNGYIXayyHY7bi4tA_bDuiNwKlkbV8R2OgMMGLk_w,7774
60
- qnty-0.1.4.dist-info/METADATA,sha256=55oIRTrDystUWnodxecG8Gbf0zx42u5wPuR00JSET_Q,6761
61
- qnty-0.1.4.dist-info/WHEEL,sha256=b4K_helf-jlQoXBBETfwnf4B04YC67LOev0jo4fX5m8,88
62
- qnty-0.1.4.dist-info/RECORD,,
60
+ qnty-0.1.5.dist-info/METADATA,sha256=LML4o5qNHxBrtupDRUGz-L9oLt8lDuZU4dVuNeevMBA,6761
61
+ qnty-0.1.5.dist-info/WHEEL,sha256=b4K_helf-jlQoXBBETfwnf4B04YC67LOev0jo4fX5m8,88
62
+ qnty-0.1.5.dist-info/RECORD,,
File without changes