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: object

A 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.

set_larger_unit(larger_unit, conversion_factor)[source]

Sets the link to a larger unit and automatically sets the reverse link.

Parameters:
  • larger_unit (Unit) – The unit that is larger than this one.

  • conversion_factor (float) – How many of this unit make one of the larger unit.

class algomancy_utils.unit.Quantity(name, standard_unit)[source]

Bases: object

A 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.

add_unit(base_unit, factor_to_base)[source]

Adds a new unit to the quantity.

Parameters:
  • base_unit (Unit) – The Unit object to add.

  • factor_to_base (float) – The conversion factor from this unit to the standard unit.

Raises:

ValueError – If a unit with the same symbol already exists.

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: object

Display 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: object

A 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.

pretty()[source]

Returns a human-friendly string representation using the configured formatter.

scale()[source]

Scales the measurement to fit within the desired digit range.

Returns:

A new scaled Measurement instance.

Return type:

Measurement

scale_to_unit(other_unit)[source]

Scale this measurement to match a target unit.

Parameters:

other_unit (Unit) – The unit to scale to.

Returns:

A new Measurement instance in the target unit.

Raises:

ValueError – If the units are not in the same quantity system.

Return type:

Measurement

class algomancy_utils.unit.QuantityRegistry[source]

Bases: object

Registry 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

register(name, quantity)[source]

Registers a custom quantity.

Parameters:
  • name (str) – The name to register the quantity under.

  • quantity (Quantity) – The Quantity object to register.

Raises:

ValueError – If a quantity with the same name is already registered.

list_quantities()[source]

Lists all registered quantity names.

Returns:

A list of strings containing all registered quantity names.

Return type:

List[str]

algomancy_utils.unit.example_usage()[source]

Example usage of the Measurement classes