SemanticUtils: Semantic Utilities#

class my.utils.SemanticUtils.SemanticUtils#

Methods for semantic-y tasks (i.e. related to data’s content rather than its form).

I Roman Numerals#

classmethod SemanticUtils.decimal_to_roman(decimal: int) → str#

Convert decimal integer to Roman numeral notation.

Handles subtractive notation (e.g., IV, IX, XL, XC, CD, CM).

Parameters:

decimal – Integer to convert (typically 1-3999).

Returns:

Roman numeral string representation.

Examples

Convert with proper subtractive notation:

>>> from my import ut
>>> ut.decimal_to_roman(1994)
'MCMXCIV'
>>> ut.decimal_to_roman(4)
'IV'
classmethod SemanticUtils.roman_to_decimal(roman: str) → int#

Convert Roman numeral notation to decimal integer.

Validates format and handles subtractive notation. Note that non-canonical additive runs that still parse (e.g. IIII) are summed rather than rejected.

Parameters:

roman – Roman numeral string, in either case.

Returns:

Decimal integer value, or 0 if invalid format.

Examples

Parse subtractive notation, case-insensitively; malformed strings yield 0:

>>> from my import ut
>>> ut.roman_to_decimal('MCMXCIV')
1994
>>> ut.roman_to_decimal('mcmxciv')
1994
>>> ut.roman_to_decimal('MXQ')
0

II Amounts#

classmethod SemanticUtils.format_amount(amount: int, unit: 'num' | 'mem' = 'num', width: int = 0) → str#

Format large numbers with SI suffixes (K, M, B) or memory units (KB, MB, GB).

Parameters:
  • amount – Number to format.

  • unit – Format type - ‘num’ for numeric (K/M/B) or ‘mem’ for memory (KB/MB/GB).

  • width – Width hint for fractional formatting. Zero rounds to a whole amount; a positive value preserves the scaled fraction.

Returns:

Formatted string with appropriate suffix.

Examples

Abbreviate counts and byte sizes, preserving useful precision on request:

>>> from my import ut
>>> ut.format_amount(2_300_000)
'2M'
>>> ut.format_amount(1_500_000, 'mem')
'2MB'
>>> ut.format_amount(1_500, width=6)
'1.500K'
>>> ut.format_amount(42)
'42'

III Pluralization#

classmethod SemanticUtils.to_singular(plural: str, overrides: list[Singularizer] | None = None) → str#

Convert plural English word to singular form.

Handles regular plurals, irregulars, and archaic forms.

Parameters:
  • plural – Plural word to convert (case-insensitive).

  • overrides – Optional list of (regex, handler) pairs to override default rules.

Returns:

Singular form of the word.

Raises:

Examples

Handle regular, irregular, and Latin/Greek plurals – case included:

>>> from my import ut
>>> ut.to_singular('cities')
'city'
>>> ut.to_singular('Geese')
'Goose'
>>> ut.to_singular('analyses')
'analysis'

Prepend custom rules via overrides:

>>> rules = ut.regex_array((r'(?i)^boxen$', lambda _: 'box'))
>>> ut.to_singular('boxen', overrides=rules)
'box'
classmethod SemanticUtils.plural(count: int | float, singular: str, plural: str | None = None) → str#

Return the singular or plural form of a word based on a count.

The counterpart of to_singular(): that goes plural -> singular; this goes the other way, from a count and a known singular (optionally with an irregular plural).

Parameters:
  • count – The count determining which form to use.

  • singular – The word’s singular form.

  • plural – The word’s irregular plural form, if singular + 's' isn’t correct.

Returns:

singular if count == 1, else plural (or singular + 's' if not given).

Examples

Regular and irregular plurals:

>>> from my import ut
>>> ut.plural(1, 'file')
'file'
>>> ut.plural(0, 'file')
'files'
>>> ut.plural(2, 'index', 'indices')
'indices'
static SemanticUtils.to_ordinal(num: int | str) → str#

Convert number to ordinal string (e.g., 1 -> ‘1st’, 2 -> ‘2nd’).

Parameters:

num – Integer or string representation of integer.

Returns:

Ordinal string with suffix (st/nd/rd/th), or empty string if input is ‘0’ or empty.

Raises:

AssertionError – If input is not a valid integer string after stripping zeros.

Examples

Pick the right suffix, teens included:

>>> from my import ut
>>> [ut.to_ordinal(n) for n in (1, 2, 3, 11, 23)]
['1st', '2nd', '3rd', '11th', '23rd']

IV Identifiers#

classmethod SemanticUtils.validate_identifier(*symbols: str) → None#

Validate that symbols are valid identifiers in Python and TypeScript.

Parameters:

*symbols – Symbol names to validate.

Raises:

AssertionError – If any symbol is a keyword or invalid identifier.

Examples

Pass silently on valid symbols, raise on reserved ones:

>>> from my import ut
>>> ut.validate_identifier('total_count')
>>> ut.validate_identifier('class')
Traceback (most recent call last):
    ...
AssertionError: Symbol class is invalid (Python keyword)