TheAlgorithms/Python · error · ValueError

{number=} must be a positive integer

Error message

{number=} must be a positive integer

What it means

Raised by is_happy_number() in maths/special_numbers/happy_number.py when number is not an int OR is <= 0 — both conditions share one check and one ValueError (unlike sibling functions that split TypeError/ValueError). The happy-number loop repeatedly sums squared digits, requiring a positive integer; str(number) digit iteration and set-cycle detection assume it. The f-string uses {number=} so the message shows e.g. "number=-19 must be a positive integer" or "number='happy'".

Source

Thrown at maths/special_numbers/happy_number.py:36

    Traceback (most recent call last):
        ...
    ValueError: number=0 must be a positive integer
    >>> is_happy_number(-19)
    Traceback (most recent call last):
        ...
    ValueError: number=-19 must be a positive integer
    >>> is_happy_number(19.1)
    Traceback (most recent call last):
        ...
    ValueError: number=19.1 must be a positive integer
    >>> is_happy_number("happy")
    Traceback (most recent call last):
        ...
    ValueError: number='happy' must be a positive integer
    """
    if not isinstance(number, int) or number <= 0:
        msg = f"{number=} must be a positive integer"
        raise ValueError(msg)

    seen = set()
    while number != 1 and number not in seen:
        seen.add(number)
        number = sum(int(digit) ** 2 for digit in str(number))
    return number == 1


if __name__ == "__main__":
    import doctest

    doctest.testmod()

View on GitHub (pinned to f5988cc097)

Solutions

  1. Validate early: if not isinstance(n, int) or n <= 0: reject input before calling
  2. Convert numeric strings: is_happy_number(int(user_input)) with try/except around the conversion
  3. Use floor division instead of true division when computing the argument

Example fix

# before
is_happy_number(input('n: '))  # str -> ValueError

# after
n = int(input('n: '))
if n > 0:
    print(is_happy_number(n))
Defensive patterns

Strategy: validation

Validate before calling

if isinstance(number, int) and not isinstance(number, bool) and number > 0:
    print(is_happy_number(number))
else:
    print('number must be a positive integer')

Type guard

def is_positive_int(value: object) -> bool:
    return isinstance(value, int) and not isinstance(value, bool) and value > 0

Try / catch

try:
    is_happy_number(number)
except ValueError as e:
    # single ValueError covers both bad type and <= 0
    logger.warning('rejected input: %s', e)

Prevention

When it happens

Trigger: Calling is_happy_number(-19), is_happy_number(0), is_happy_number(19.1), or is_happy_number('happy'). Any non-int (including floats and strings) or any int <= 0 raises. Note the doctest labels 19.1 and 'happy' as ValueError, not TypeError — plan exception handling accordingly.

Common situations: Unparsed user input passed straight through; float division results; 0 from empty-count defaults. Since one ValueError covers both bad type and bad range, a single except clause suffices — but you cannot distinguish cause from the exception alone.

Related errors


AI-assisted analysis of TheAlgorithms/Python@f5988cc097 (2026-08-14). Data as JSON: /api/errors/81d9f33517344552. Report an issue: GitHub.