Unit framework¶
Overview¶
This module provides a small, self-contained framework to represent quantities, units, and measured values with smart, human-friendly formatting. It is used throughout the project (notably in KPI templates) to present values using the most appropriate unit and number of digits without writing formatting logic in multiple places.
Core concepts¶
Quantity: A domain of measurement (e.g., Length, Time, Data). A quantity owns a chain of related units and knows how they convert.
Unit: A single unit with a symbol (e.g., m, s, B). Units are linked from smaller to larger and vice versa so values can scale up or down.
BaseMeasurement: A formatting preference object: it stores the base unit for a value and how it should be displayed (min/max significant digits and decimal places, optional smallest/largest unit clamps).
Measurement: A concrete value bound to a BaseMeasurement. It can be scaled to a better unit and formatted with the desired precision.
Why this exists¶
Displaying 15320.0 seconds as “4.26 h” or 12_345_678 B as “11.77 MiB” should be
trivial for users of the framework, and consistent across the app. This module
centralizes unit chains, conversions, and pretty-printing so KPIs and UI code
just construct a Measurement and call pretty().
Formatting Preferences¶
min_digits / max_digits bound the number of significant digits before a unit change is attempted. This keeps values compact while avoiding “0.00” noise.
decimals controls the decimal places in the final formatted string.
smallest_unit / largest_unit can be set to restrict automatic scaling range.
Examples¶
Example: length
TODO Explain example
1 from algomancy_utils.unit import QUANTITIES, BaseMeasurement, Measurement
2
3 length = QUANTITIES["length"]
4 length_m = BaseMeasurement(
5 base_unit=length["m"],
6 min_digits=1,
7 max_digits=3,
8 decimals=2
9 )
10 for val in [0.000005, 0.025, 2.5, 250, 25_000, 2_500_000]:
11 m = Measurement(length_m, val)
12 print(m.pretty())
>> 5.00 μm
>> 25.12 mm
>> 2.50 m
>> 250.00 m
>> 25.00 km
>> 2.50 Mm
Example: Time with tighter bounds
TODO Explain example
1time = QUANTITIES["time"]
2# Clamp scaling between seconds and hours, show 1 decimal
3prefs = BaseMeasurement(
4 base_unit=time["s"],
5 min_digits=1,
6 max_digits=2,
7 decimals=1,
8 smallest_unit="s",
9 largest_unit="h"
10 )
11for val in [0.5, 45, 3_665, 86_400]:
12 print(Measurement(prefs, val).pretty())
>> 0.5 s
>> 45.0 s
>> 1.0 h
>> 24.0 h
Example: Money
TODO Explain example
1money = QUANTITIES["money"]
2usd = BaseMeasurement(
3 base_unit=money["$"],
4 min_digits=0,
5 max_digits=3,
6 decimals=2
7 )
8print(Measurement(usd, 1_234_567).pretty())
>> $1.23M
Reference¶
- class algomancy_utils.unit.Unit(symbol)[source]¶
Bases:
objectA single unit in a quantity (e.g., m, s, B).
A Unit knows its printable symbol and can be linked to an adjacent smaller or larger unit with known conversion factors. These links are used by Measurement to automatically scale values up or down to keep within the configured digit bounds.
- Parameters:
symbol (str) – The printable symbol for the unit.
Notes
Links are set when units are added to a Quantity via Quantity.add_unit(…). You generally don’t set them manually.
conversion_factor_to_larger represents how many of the current unit make one of the larger unit. The reverse factor is stored on the larger unit to point back to the smaller.
- class algomancy_utils.unit.Quantity(name, standard_unit)[source]¶
Bases:
objectA domain of measurement that owns and links units.
A Quantity groups a set of related Unit`s (e.g., meters, kilometers for length; seconds, hours for time) and stores their conversion relationships in increasing order. It provides convenient access by unit name via `quantity[“m”] and is responsible for wiring the chain of smaller/larger units so values can scale automatically.
- Parameters:
name (str) – The name of the quantity.
standard_unit (Unit) – The standard (base) unit for this quantity.
Notes
Units are sorted by their factor relative to the standard/base unit you provide when adding them.
When you add a new unit, bidirectional links between adjacent units are re-built automatically.
- class algomancy_utils.unit.BaseMeasurement(base_unit, min_digits=0, max_digits=3, decimals=2, smallest_unit=None, largest_unit=None, formatter=None, use_scaling=True)[source]¶
Bases:
objectDisplay and scaling preferences for measurements.
A BaseMeasurement binds a base Unit with formatting and scaling rules that Measurement instances will follow when pretty-printing values.
- Parameters:
base_unit (Unit) – The unit in which input values are expressed (e.g., seconds, meters, bytes). Auto-scaling starts from this unit.
min_digits (int) – Minimum number of significant digits to keep before trying to scale down to a smaller unit. Helps avoid values like “0.00”. Defaults to 0.
max_digits (int) – Maximum number of significant digits to allow before trying to scale up to a larger unit. Keeps values compact (e.g., 2500 m -> 2.5 km). Defaults to 3.
decimals (int) – Number of decimal places to show in the final formatted string. Defaults to 2.
smallest_unit (str | None) – Optional symbol of the smallest allowed unit for scaling.
largest_unit (str | None) – Optional symbol of the largest allowed unit for scaling.
formatter (Callable[[Measurement], str] | None) – Optional custom function to format the Measurement.
use_scaling (bool) – Whether to enable automatic unit scaling. Defaults to True.
Notes
This class contains no value; it is reused across many Measurement instances that share the same formatting rules.
If smallest_unit/largest_unit are provided, they must match unit symbols registered in the corresponding Quantity.
- property default_formatter: Callable[[Measurement], str]¶
Returns the default formatting function.
- property formatter: Callable[[Measurement], str]¶
Returns the active formatter (either custom or default).
- class algomancy_utils.unit.Measurement(base_measurement, value=-9999999999, max_decimals=10)[source]¶
Bases:
objectA value bound to display rules with auto-scaling and pretty output.
Measurement holds a numeric value together with a BaseMeasurement (formatting/scaling preferences) and the current Unit.
- Parameters:
base_measurement (BaseMeasurement) – The BaseMeasurement with rules for formatting/scaling.
value (float) – The numeric value, expressed in base_measurement.unit unless scaled. Defaults to INITIAL_VALUE.
max_decimals – Maximum number of decimal places to show. Defaults to MAX_DECIMALS.
Example
>>> length = QUANTITIES["length"] >>> prefs = BaseMeasurement(length["m"], min_digits=1, max_digits=3, decimals=2) >>> m = Measurement(prefs, 2500) >>> print(m.pretty()) 2.50 km
- get_display_measurement()[source]¶
Returns a scaled measurement for display purposes if scaling is enabled.
- scale()[source]¶
Scales the measurement to fit within the desired digit range.
- Returns:
A new scaled Measurement instance.
- Return type:
- class algomancy_utils.unit.QuantityRegistry[source]¶
Bases:
objectRegistry for commonly used quantities.
Provides convenient access to pre-defined Quantity objects and a simple way to register custom ones. Use the global instance QUANTITIES to look up quantities by name, e.g., QUANTITIES[“length”].
- Built-in quantities (keys):
length, mass, time, area, volume, speed, temperature, energy, power, pressure, frequency, data (binary multiples), data_decimal (decimal SI), money, percentage, count, current, voltage, resistance, default
- Customization:
Create a Quantity, add units with add_unit(…), then register it via register(name, quantity). Afterwards it can be retrieved with the same index syntax: QUANTITIES[name].
- get(name)[source]¶
Retrieves a quantity by name.
- Parameters:
name (str) – The name of the quantity to retrieve.
- Returns:
The Quantity object if found, otherwise None.
- Return type:
Quantity | None