qnty 0.0.9__py3-none-any.whl → 0.1.0__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.
Files changed (92) hide show
  1. qnty/__init__.py +2 -3
  2. qnty/constants/__init__.py +10 -0
  3. qnty/constants/numerical.py +18 -0
  4. qnty/constants/solvers.py +6 -0
  5. qnty/constants/tests.py +6 -0
  6. qnty/dimensions/__init__.py +23 -0
  7. qnty/dimensions/base.py +97 -0
  8. qnty/dimensions/field_dims.py +126 -0
  9. qnty/dimensions/field_dims.pyi +128 -0
  10. qnty/dimensions/signature.py +111 -0
  11. qnty/equations/__init__.py +1 -1
  12. qnty/equations/equation.py +118 -155
  13. qnty/equations/system.py +68 -65
  14. qnty/expressions/__init__.py +25 -46
  15. qnty/expressions/formatter.py +188 -0
  16. qnty/expressions/functions.py +46 -68
  17. qnty/expressions/nodes.py +539 -384
  18. qnty/expressions/types.py +70 -0
  19. qnty/problems/__init__.py +145 -0
  20. qnty/problems/composition.py +1031 -0
  21. qnty/problems/problem.py +695 -0
  22. qnty/problems/rules.py +145 -0
  23. qnty/problems/solving.py +1216 -0
  24. qnty/problems/validation.py +127 -0
  25. qnty/quantities/__init__.py +28 -5
  26. qnty/quantities/base_qnty.py +677 -0
  27. qnty/quantities/field_converters.py +24004 -0
  28. qnty/quantities/field_qnty.py +1012 -0
  29. qnty/{generated/setters.py → quantities/field_setter.py} +3071 -2961
  30. qnty/{generated/quantities.py → quantities/field_vars.py} +754 -432
  31. qnty/{generated/quantities.pyi → quantities/field_vars.pyi} +1289 -1290
  32. qnty/solving/manager.py +50 -44
  33. qnty/solving/order.py +181 -133
  34. qnty/solving/solvers/__init__.py +2 -9
  35. qnty/solving/solvers/base.py +27 -37
  36. qnty/solving/solvers/iterative.py +115 -135
  37. qnty/solving/solvers/simultaneous.py +93 -165
  38. qnty/units/__init__.py +1 -0
  39. qnty/{generated/units.py → units/field_units.py} +1700 -991
  40. qnty/units/field_units.pyi +2461 -0
  41. qnty/units/prefixes.py +58 -105
  42. qnty/units/registry.py +76 -89
  43. qnty/utils/__init__.py +16 -0
  44. qnty/utils/caching/__init__.py +23 -0
  45. qnty/utils/caching/manager.py +401 -0
  46. qnty/utils/error_handling/__init__.py +66 -0
  47. qnty/utils/error_handling/context.py +39 -0
  48. qnty/utils/error_handling/exceptions.py +96 -0
  49. qnty/utils/error_handling/handlers.py +171 -0
  50. qnty/utils/logging.py +4 -4
  51. qnty/utils/protocols.py +164 -0
  52. qnty/utils/scope_discovery.py +420 -0
  53. {qnty-0.0.9.dist-info → qnty-0.1.0.dist-info}/METADATA +1 -1
  54. qnty-0.1.0.dist-info/RECORD +60 -0
  55. qnty/_backup/problem_original.py +0 -1251
  56. qnty/_backup/quantity.py +0 -63
  57. qnty/codegen/cli.py +0 -125
  58. qnty/codegen/generators/data/unit_data.json +0 -8807
  59. qnty/codegen/generators/data_processor.py +0 -345
  60. qnty/codegen/generators/dimensions_gen.py +0 -434
  61. qnty/codegen/generators/doc_generator.py +0 -141
  62. qnty/codegen/generators/out/dimension_mapping.json +0 -974
  63. qnty/codegen/generators/out/dimension_metadata.json +0 -123
  64. qnty/codegen/generators/out/units_metadata.json +0 -223
  65. qnty/codegen/generators/quantities_gen.py +0 -159
  66. qnty/codegen/generators/setters_gen.py +0 -178
  67. qnty/codegen/generators/stubs_gen.py +0 -167
  68. qnty/codegen/generators/units_gen.py +0 -295
  69. qnty/expressions/cache.py +0 -94
  70. qnty/generated/dimensions.py +0 -514
  71. qnty/problem/__init__.py +0 -91
  72. qnty/problem/base.py +0 -142
  73. qnty/problem/composition.py +0 -385
  74. qnty/problem/composition_mixin.py +0 -382
  75. qnty/problem/equations.py +0 -413
  76. qnty/problem/metaclass.py +0 -302
  77. qnty/problem/reconstruction.py +0 -1016
  78. qnty/problem/solving.py +0 -180
  79. qnty/problem/validation.py +0 -64
  80. qnty/problem/variables.py +0 -239
  81. qnty/quantities/expression_quantity.py +0 -314
  82. qnty/quantities/quantity.py +0 -428
  83. qnty/quantities/typed_quantity.py +0 -215
  84. qnty/validation/__init__.py +0 -0
  85. qnty/validation/registry.py +0 -0
  86. qnty/validation/rules.py +0 -167
  87. qnty-0.0.9.dist-info/RECORD +0 -63
  88. /qnty/{codegen → extensions}/__init__.py +0 -0
  89. /qnty/{codegen/generators → extensions/integration}/__init__.py +0 -0
  90. /qnty/{codegen/generators/utils → extensions/plotting}/__init__.py +0 -0
  91. /qnty/{generated → extensions/reporting}/__init__.py +0 -0
  92. {qnty-0.0.9.dist-info → qnty-0.1.0.dist-info}/WHEEL +0 -0
@@ -1,434 +0,0 @@
1
- #!/usr/bin/env python3
2
- """
3
- Dimension generator for qnty library.
4
-
5
- This script generates the dimensions.py file from unit_data.json, creating
6
- all necessary dimension signatures programmatically without hardcoding.
7
- """
8
-
9
- import json
10
- from pathlib import Path
11
- from typing import Any
12
-
13
- # Configuration
14
- BASE_DIMENSIONS = {
15
- 'LENGTH': {'prime': 2, 'params': {'length': 1}},
16
- 'MASS': {'prime': 3, 'params': {'mass': 1}},
17
- 'TIME': {'prime': 5, 'params': {'time': 1}},
18
- 'CURRENT': {'prime': 7, 'params': {'current': 1}},
19
- 'TEMPERATURE': {'prime': 11, 'params': {'temp': 1}},
20
- 'AMOUNT': {'prime': 13, 'params': {'amount': 1}},
21
- 'LUMINOSITY': {'prime': 17, 'params': {'luminosity': 1}},
22
- 'DIMENSIONLESS': {'prime': 1, 'params': {}},
23
- }
24
-
25
- DIMENSION_SYMBOLS = {
26
- 'length': 'L',
27
- 'mass': 'M',
28
- 'time': 'T',
29
- 'current': 'A',
30
- 'temp': 'Θ',
31
- 'amount': 'N',
32
- 'luminosity': 'J',
33
- }
34
-
35
- # All dimensions will be explicitly defined - no lazy loading needed
36
-
37
-
38
- class DimensionGenerator:
39
- """Generator for dimensions.py file."""
40
-
41
- def __init__(self, data_path: Path, output_path: Path, out_dir: Path):
42
- """Initialize with paths."""
43
- self.data_path = data_path
44
- self.output_path = output_path
45
- self.out_dir = out_dir
46
- self.out_dir.mkdir(parents=True, exist_ok=True)
47
-
48
- # Load unit data
49
- with open(self.data_path, encoding='utf-8') as f:
50
- self.unit_data: dict[str, Any] = json.load(f)
51
-
52
- # Track all discovered dimensions
53
- self.all_dimensions: dict[str, dict[str, int]] = {}
54
- self.common_signatures: dict[tuple[int, ...], float] = {} # For cache optimization
55
-
56
- def calculate_signature(self, dims: dict[str, int]) -> float:
57
- """Calculate prime factorization signature for dimensions."""
58
- if not dims:
59
- return 1.0
60
-
61
- signature = 1.0
62
- prime_map = {
63
- 'length': 2,
64
- 'mass': 3,
65
- 'time': 5,
66
- 'current': 7,
67
- 'temp': 11,
68
- 'amount': 13,
69
- 'luminosity': 17,
70
- }
71
-
72
- for dim_name, power in dims.items():
73
- if power != 0 and dim_name in prime_map:
74
- signature *= prime_map[dim_name] ** power
75
-
76
- return signature
77
-
78
- def tuple_from_dims(self, dims: dict[str, int]) -> tuple[int, ...]:
79
- """Create ordered tuple for dimension cache key."""
80
- return (
81
- dims.get('length', 0),
82
- dims.get('mass', 0),
83
- dims.get('time', 0),
84
- dims.get('current', 0),
85
- dims.get('temp', 0),
86
- dims.get('amount', 0),
87
- dims.get('luminosity', 0),
88
- )
89
-
90
- def format_dimension_comment(self, dims: dict[str, int]) -> str:
91
- """Create readable comment for a dimension."""
92
- if not dims:
93
- return "Dimensionless"
94
-
95
- parts = []
96
- for dim, power in sorted(dims.items()):
97
- if power != 0:
98
- symbol = DIMENSION_SYMBOLS.get(dim, dim[0].upper())
99
- if power == 1:
100
- parts.append(symbol)
101
- else:
102
- parts.append(f"{symbol}^{power}")
103
-
104
- return ' '.join(parts) if parts else "Dimensionless"
105
-
106
- def extract_all_dimensions(self) -> None:
107
- """Extract all unique dimensions from unit data."""
108
- # Add base dimensions
109
- for name, config in BASE_DIMENSIONS.items():
110
- self.all_dimensions[name] = config['params']
111
-
112
- # Extract from unit data
113
- for field_name, field_data in self.unit_data.items():
114
- dims = field_data.get('dimensions', {})
115
- name = field_name.upper()
116
-
117
- # Skip if it's a base dimension
118
- if name not in BASE_DIMENSIONS:
119
- self.all_dimensions[name] = dims
120
-
121
- # Build common signatures cache (programmatically)
122
- for _name, dims in self.all_dimensions.items():
123
- dim_tuple = self.tuple_from_dims(dims)
124
- signature = self.calculate_signature(dims)
125
- self.common_signatures[dim_tuple] = signature
126
-
127
- def generate_common_signatures_dict(self) -> list[str]:
128
- """Generate the _COMMON_SIGNATURES dictionary programmatically."""
129
- lines = []
130
- lines.append(" # Pre-computed signature cache for common dimensions")
131
- lines.append(" _COMMON_SIGNATURES: ClassVar[dict[tuple[int, ...], int | float]] = {")
132
-
133
- # Sort by complexity (number of non-zero dimensions) and then alphabetically
134
- sorted_sigs = sorted(self.common_signatures.items(),
135
- key=lambda x: (sum(abs(v) for v in x[0]), x[0]))
136
-
137
- # Limit to most common ones to avoid huge cache
138
- max_cache_entries = 50
139
- for dim_tuple, signature in sorted_sigs[:max_cache_entries]:
140
- # Find dimensions with this signature for comment
141
- matching_dims = [name for name, dims in self.all_dimensions.items()
142
- if self.tuple_from_dims(dims) == dim_tuple]
143
-
144
- if matching_dims:
145
- # Pick the shortest/most descriptive name
146
- best_name = min(matching_dims, key=len)
147
- dims = self.all_dimensions[best_name]
148
- comment = self.format_dimension_comment(dims)
149
-
150
- # Format the signature value nicely
151
- if signature == int(signature):
152
- sig_str = str(int(signature))
153
- else:
154
- sig_str = f"{signature:.10g}" # Use general format to avoid long decimals
155
-
156
- lines.append(f" {dim_tuple}: {sig_str}, # {comment}")
157
-
158
- lines.append(" }")
159
-
160
- return lines
161
-
162
- def generate_header(self) -> list[str]:
163
- """Generate the file header."""
164
- lines = [
165
- '"""',
166
- 'Dimension System',
167
- '================',
168
- '',
169
- 'Compile-time dimensional analysis using type system for ultra-fast operations.',
170
- '',
171
- 'This file is auto-generated by codegen/generators/dimensions_gen.py',
172
- 'DO NOT EDIT MANUALLY - changes will be overwritten.',
173
- '"""',
174
- '',
175
- 'from dataclasses import dataclass',
176
- 'from enum import IntEnum',
177
- 'from typing import ClassVar, final',
178
- '',
179
- '',
180
- ]
181
- return lines
182
-
183
- def generate_base_dimension_class(self) -> list[str]:
184
- """Generate the BaseDimension IntEnum."""
185
- lines = [
186
- 'class BaseDimension(IntEnum):',
187
- ' """Base dimensions as prime numbers for efficient bit operations."""',
188
- ]
189
-
190
- for name, config in BASE_DIMENSIONS.items():
191
- if name == 'DIMENSIONLESS':
192
- lines.append(f" {name} = {config['prime']} # Must be 1 to act as multiplicative identity")
193
- else:
194
- lines.append(f" {name} = {config['prime']}")
195
-
196
- lines.extend(['', ''])
197
- return lines
198
-
199
- def generate_dimension_signature_class(self) -> list[str]:
200
- """Generate the DimensionSignature class."""
201
- lines = [
202
- '@final',
203
- '@dataclass(frozen=True, slots=True)',
204
- 'class DimensionSignature:',
205
- ' """Immutable dimension signature for zero-cost dimensional analysis."""',
206
- ' ',
207
- ' # Store as bit pattern for ultra-fast comparison',
208
- ' _signature: int | float = 1',
209
- ' ',
210
- ]
211
-
212
- # Add common signatures cache
213
- lines.extend(self.generate_common_signatures_dict())
214
-
215
- lines.extend([
216
- ' ',
217
- ' # Instance cache for interning common dimensions',
218
- ' _INSTANCE_CACHE: ClassVar[dict[int | float, "DimensionSignature"]] = {}',
219
- ' ',
220
- ' def __new__(cls, signature: int | float = 1):',
221
- ' """Optimized constructor with instance interning."""',
222
- ' if signature in cls._INSTANCE_CACHE:',
223
- ' return cls._INSTANCE_CACHE[signature]',
224
- ' ',
225
- ' instance = object.__new__(cls)',
226
- ' ',
227
- ' # Cache common signatures',
228
- ' if len(cls._INSTANCE_CACHE) < 100: # Limit cache size',
229
- ' cls._INSTANCE_CACHE[signature] = instance',
230
- ' ',
231
- ' return instance',
232
- ' ',
233
- ' @classmethod',
234
- ' def create(cls, length=0, mass=0, time=0, current=0, temp=0, amount=0, luminosity=0):',
235
- ' """Create dimension from exponents with optimized lookup."""',
236
- ' # Check cache first',
237
- ' key = (length, mass, time, current, temp, amount, luminosity)',
238
- ' if key in cls._COMMON_SIGNATURES:',
239
- ' return cls(cls._COMMON_SIGNATURES[key])',
240
- ' ',
241
- ' # Fast path for dimensionless',
242
- ' if not any([length, mass, time, current, temp, amount, luminosity]):',
243
- ' return cls(1)',
244
- ' ',
245
- ' # Compute signature',
246
- ' signature = 1',
247
- ' if length != 0:',
248
- ' signature *= BaseDimension.LENGTH ** length',
249
- ' if mass != 0:',
250
- ' signature *= BaseDimension.MASS ** mass',
251
- ' if time != 0:',
252
- ' signature *= BaseDimension.TIME ** time',
253
- ' if current != 0:',
254
- ' signature *= BaseDimension.CURRENT ** current',
255
- ' if temp != 0:',
256
- ' signature *= BaseDimension.TEMPERATURE ** temp',
257
- ' if amount != 0:',
258
- ' signature *= BaseDimension.AMOUNT ** amount',
259
- ' if luminosity != 0:',
260
- ' signature *= BaseDimension.LUMINOSITY ** luminosity',
261
- ' ',
262
- ' return cls(signature)',
263
- ' ',
264
- ' def __mul__(self, other):',
265
- ' """Multiply dimensions."""',
266
- ' return DimensionSignature(self._signature * other._signature)',
267
- ' ',
268
- ' def __truediv__(self, other):',
269
- ' """Divide dimensions."""',
270
- ' return DimensionSignature(self._signature / other._signature)',
271
- ' ',
272
- ' def __pow__(self, power):',
273
- ' """Raise dimension to a power."""',
274
- ' if power == 1:',
275
- ' return self',
276
- ' if power == 0:',
277
- ' return DimensionSignature(1)',
278
- ' return DimensionSignature(self._signature ** power)',
279
- ' ',
280
- ' def is_compatible(self, other):',
281
- ' """Check dimensional compatibility."""',
282
- ' return self._signature == other._signature',
283
- ' ',
284
- ' def __eq__(self, other):',
285
- ' """Check equality."""',
286
- ' if self is other:',
287
- ' return True',
288
- ' return isinstance(other, DimensionSignature) and self._signature == other._signature',
289
- ' ',
290
- ' def __hash__(self):',
291
- ' """Hash based on signature."""',
292
- ' return hash(self._signature)',
293
- '',
294
- '',
295
- ])
296
-
297
- return lines
298
-
299
- def generate_dimension_constants(self) -> list[str]:
300
- """Generate dimension constant definitions."""
301
- lines = []
302
-
303
- # Generate signature lookup dictionary
304
- lines.append('# Pre-computed dimension signatures for all dimensions')
305
- lines.append('_DIMENSION_SIGNATURES = {')
306
-
307
- for name in sorted(self.all_dimensions.keys()):
308
- dims = self.all_dimensions[name]
309
- signature = self.calculate_signature(dims)
310
- comment = self.format_dimension_comment(dims)
311
-
312
- if signature == int(signature):
313
- sig_str = str(int(signature))
314
- else:
315
- sig_str = f"{signature:.10g}"
316
-
317
- lines.append(f' "{name}": {sig_str}, # {comment}')
318
-
319
- lines.append('}')
320
- lines.append('')
321
-
322
- # Lazy loading infrastructure
323
- lines.extend([
324
- '# Lazy loading cache',
325
- '_dimension_cache: dict[str, DimensionSignature] = {}',
326
- '',
327
- 'def __getattr__(name: str) -> DimensionSignature:',
328
- ' """Lazy load dimension constants."""',
329
- ' if name in _DIMENSION_SIGNATURES:',
330
- ' if name not in _dimension_cache:',
331
- ' _dimension_cache[name] = DimensionSignature(_DIMENSION_SIGNATURES[name])',
332
- ' return _dimension_cache[name]',
333
- ' raise AttributeError(f"module {__name__!r} has no attribute {name!r}")',
334
- '',
335
- ])
336
-
337
- # Generate ALL dimensions found in unit data - no hardcoded mappings
338
- lines.append('# All dimension constants generated from unit data')
339
-
340
- # Generate constants for ALL fields in the JSON data
341
- for field_name in sorted(self.unit_data.keys()):
342
- field_data = self.unit_data[field_name]
343
- dims = field_data.get('dimensions', {})
344
- const_name = field_name.upper()
345
-
346
- signature = self.calculate_signature(dims)
347
- comment = self.format_dimension_comment(dims)
348
-
349
- if signature == int(signature):
350
- sig_str = str(int(signature))
351
- else:
352
- sig_str = f"{signature:.10g}"
353
-
354
- lines.append(f'{const_name} = DimensionSignature({sig_str}) # {comment}')
355
-
356
- lines.append('')
357
-
358
- return lines
359
-
360
- def generate_exports(self) -> list[str]:
361
- """Generate __all__ export list."""
362
- lines = [
363
- '# Module exports',
364
- '__all__ = [',
365
- ' "BaseDimension",',
366
- ' "DimensionSignature",',
367
- ]
368
-
369
- # Add all dimensions from unit data
370
- for field_name in sorted(self.unit_data.keys()):
371
- const_name = field_name.upper()
372
- lines.append(f' "{const_name}",')
373
-
374
- lines.extend([
375
- ']',
376
- '',
377
- ])
378
-
379
- return lines
380
-
381
- def generate(self) -> None:
382
- """Generate the complete dimensions.py file."""
383
- # Extract all dimensions from data
384
- self.extract_all_dimensions()
385
-
386
- # Build the file content
387
- lines = []
388
- lines.extend(self.generate_header())
389
- lines.extend(self.generate_base_dimension_class())
390
- lines.extend(self.generate_dimension_signature_class())
391
- lines.extend(self.generate_dimension_constants())
392
- lines.extend(self.generate_exports())
393
-
394
- # Write the file with newline at end
395
- content = '\n'.join(lines) + '\n'
396
- self.output_path.write_text(content, encoding='utf-8')
397
- print(f"Generated {self.output_path}")
398
-
399
- # Save metadata to out directory
400
- metadata = {
401
- 'total_dimensions': len(self.all_dimensions),
402
- 'generated_dimensions': sorted(self.unit_data.keys()),
403
- 'base_dimensions': list(BASE_DIMENSIONS.keys()),
404
- 'signatures_cached': len(self.common_signatures),
405
- }
406
-
407
- metadata_path = self.out_dir / 'dimension_metadata.json'
408
- with open(metadata_path, 'w', encoding='utf-8') as f:
409
- json.dump(metadata, f, indent=2)
410
- print(f"Saved metadata to {metadata_path}")
411
-
412
-
413
- def main() -> None:
414
- """Main entry point."""
415
- # Set up paths
416
- generator_dir = Path(__file__).parent
417
- data_path = generator_dir / 'data' / 'unit_data.json'
418
- output_path = generator_dir.parent.parent / 'generated' / 'dimensions.py'
419
- out_dir = generator_dir / 'out'
420
-
421
- # Create output directory if needed
422
- output_path.parent.mkdir(parents=True, exist_ok=True)
423
-
424
- # Run generator
425
- generator = DimensionGenerator(data_path, output_path, out_dir)
426
- generator.generate()
427
-
428
- print("\nDimension generation complete!")
429
- print(f" - Total dimensions: {len(generator.all_dimensions)}")
430
- print(f" - Cached signatures: {len(generator.common_signatures)}")
431
-
432
-
433
- if __name__ == "__main__":
434
- main()
@@ -1,141 +0,0 @@
1
- """
2
- Documentation Generation Helper
3
- ==============================
4
-
5
- Shared functions for generating consistent documentation across
6
- quantities.py and quantities.pyi files.
7
- """
8
-
9
- try:
10
- from .data_processor import get_unit_names_and_aliases
11
- except ImportError:
12
- # Handle standalone execution
13
- from .data_processor import get_unit_names_and_aliases
14
-
15
-
16
- def generate_class_docstring(class_name: str, display_name: str, units: list, is_dimensionless: bool = False) -> list[str]:
17
- """Generate comprehensive class docstring for quantity classes."""
18
- # Get example units for documentation
19
- example_units = []
20
- for unit in units[:3]: # Take first 3 units as examples
21
- primary_name, _ = get_unit_names_and_aliases(unit)
22
- example_units.append(f'"{primary_name}"')
23
-
24
- unit_examples = ', '.join(example_units) if example_units else '"unit"'
25
-
26
- lines = [
27
- ' """',
28
- f' Type-safe {display_name} quantity with expression capabilities.',
29
- ' ',
30
- ]
31
-
32
- if is_dimensionless:
33
- lines.extend([
34
- ' Constructor Options:',
35
- ' -------------------',
36
- f' - {class_name}("variable_name") -> Create unknown {display_name}',
37
- f' - {class_name}(value, "variable_name") -> Create known {display_name}',
38
- ' ',
39
- ' Examples:',
40
- ' ---------',
41
- f' >>> unknown = {class_name}("efficiency") # Unknown {display_name}',
42
- f' >>> known = {class_name}(0.85, "thermal_efficiency") # Known {display_name}',
43
- ])
44
- else:
45
- lines.extend([
46
- ' Constructor Options:',
47
- ' -------------------',
48
- f' - {class_name}("variable_name") -> Create unknown {display_name}',
49
- f' - {class_name}(value, "unit", "variable_name") -> Create known {display_name}',
50
- ' ',
51
- ' Examples:',
52
- ' ---------',
53
- f' >>> unknown = {class_name}("pressure") # Unknown {display_name}',
54
- f' >>> known = {class_name}(100, {unit_examples.split(",")[0] if unit_examples else "unit"}, "inlet_pressure") # Known {display_name}',
55
- ' ',
56
- f' Available units: {unit_examples}',
57
- ])
58
-
59
- lines.append(' """')
60
- return lines
61
-
62
-
63
- def generate_init_method(class_name: str, display_name: str, is_dimensionless: bool = False, stub_only: bool = False) -> list[str]:
64
- """Generate __init__ method with proper type hints."""
65
- del class_name # Unused but kept for API compatibility
66
- lines = []
67
-
68
- if is_dimensionless:
69
- lines.append(' def __init__(self, name_or_value: str | int | float, name: str | None = None, is_known: bool = True):')
70
- if not stub_only:
71
- lines.extend([
72
- ' """',
73
- f' Initialize {display_name} quantity.',
74
- ' ',
75
- ' Args:',
76
- ' name_or_value: Variable name (str) if unknown, or value (int/float) if known',
77
- ' name: Variable name (required if providing value)',
78
- ' is_known: Whether the variable has a known value',
79
- ' """',
80
- ' if name is None:',
81
- ' # Single argument: name only (unknown variable)',
82
- ' super().__init__(name_or_value, is_known=is_known)',
83
- ' else:',
84
- ' # Two arguments: value and name (known variable)',
85
- ' super().__init__(name_or_value, name, is_known=is_known)',
86
- ])
87
- else:
88
- lines.append(' ...')
89
- else:
90
- lines.append(' def __init__(self, name_or_value: str | int | float, unit: str | None = None, name: str | None = None, is_known: bool = True):')
91
- if not stub_only:
92
- lines.extend([
93
- ' """',
94
- f' Initialize {display_name} quantity.',
95
- ' ',
96
- ' Args:',
97
- ' name_or_value: Variable name (str) if unknown, or value (int/float) if known',
98
- ' unit: Unit string (required if providing value)',
99
- ' name: Variable name (required if providing value)',
100
- ' is_known: Whether the variable has a known value',
101
- ' """',
102
- ' if unit is None and name is None:',
103
- ' # Single argument: name only (unknown variable)',
104
- ' super().__init__(name_or_value, is_known=is_known)',
105
- ' elif unit is not None and name is not None:',
106
- ' # Three arguments: value, unit, name (known variable)',
107
- ' super().__init__(name_or_value, unit, name, is_known=is_known)',
108
- ' else:',
109
- ' raise ValueError("Must provide either just name (unknown) or value, unit, and name (known)")',
110
- ])
111
- else:
112
- lines.append(' ...')
113
-
114
- return lines
115
-
116
-
117
- def generate_set_method(setter_class_name: str, display_name: str, stub_only: bool = False) -> list[str]:
118
- """Generate set method with comprehensive documentation."""
119
- lines = [
120
- f' def set(self, value: int | float) -> ts.{setter_class_name}:',
121
- ' """',
122
- f' Create a setter for this {display_name} quantity.',
123
- ' ',
124
- ' Args:',
125
- ' value: The numeric value to set',
126
- ' ',
127
- ' Returns:',
128
- f' {setter_class_name}: A setter with unit properties like .meters, .inches, etc.',
129
- ' ',
130
- ' Example:',
131
- ' >>> length = Length("beam_length")',
132
- ' >>> length.set(100).millimeters # Sets to 100 mm',
133
- ' """',
134
- ]
135
-
136
- if stub_only:
137
- lines.append(' ...')
138
- else:
139
- lines.append(f' return ts.{setter_class_name}(self, value)')
140
-
141
- return lines