TheAlgorithms/Python · error · TypeError

Purchase value must be numeric

Error message

Purchase value must be numeric

What it means

Raised by straight_line_depreciation() when purchase_value is not int or float (TypeError). The arithmetic (purchase - residual, division by years) requires a real number, so strings, None, and Decimal are rejected before any math. bool passes because bool subclasses int.

Source

Thrown at financial/straight_line_depreciation.py:62

    [100.0, 100.0, 100.0, 100.0, 100.0, 100.0, 100.0, 100.0, 100.0, 100.0]
    >>> straight_line_depreciation(6, 1250.0, 50.0)
    [200.0, 200.0, 200.0, 200.0, 200.0, 200.0]
    >>> straight_line_depreciation(4, 1001.0)
    [250.25, 250.25, 250.25, 250.25]
    >>> straight_line_depreciation(11, 380.0, 50.0)
    [30.0, 30.0, 30.0, 30.0, 30.0, 30.0, 30.0, 30.0, 30.0, 30.0, 30.0]
    >>> straight_line_depreciation(1, 4985, 100)
    [4885.0]
    """

    if not isinstance(useful_years, int):
        raise TypeError("Useful years must be an integer")

    if useful_years < 1:
        raise ValueError("Useful years cannot be less than 1")

    if not isinstance(purchase_value, (float, int)):
        raise TypeError("Purchase value must be numeric")

    if not isinstance(residual_value, (float, int)):
        raise TypeError("Residual value must be numeric")

    if purchase_value < 0.0:
        raise ValueError("Purchase value cannot be less than zero")

    if purchase_value < residual_value:
        raise ValueError("Purchase value cannot be less than residual value")

    # Calculate annual depreciation expense
    depreciable_cost = purchase_value - residual_value
    annual_depreciation_expense = depreciable_cost / useful_years

    # List of annual depreciation expenses
    list_of_depreciation_expenses = []
    accumulated_depreciation_expense = 0.0
    for period in range(useful_years):

View on GitHub (pinned to f5988cc097)

Solutions

  1. Convert to float before calling: float(purchase_value) — mind precision for money-critical use.
  2. Better: keep money in int cents if precision matters; this API accepts plain numbers only.
  3. Fix ingestion: parse numeric fields at the edge, never in the accounting core.

Example fix

# before
straight_line_depreciation(5, row['purchase_value'], 50.0)  # row value is '1250.0'

# after
straight_line_depreciation(5, float(row['purchase_value']), 50.0)
Defensive patterns

Strategy: type-guard

Validate before calling

if not isinstance(purchase_value, (int, float)) or isinstance(purchase_value, bool):
    purchase_value = float(purchase_value)  # or raise
straight_line_depreciation(5, purchase_value, 50.0)

Type guard

def is_numeric(v: object) -> bool:
    return isinstance(v, (int, float)) and not isinstance(v, bool)

Try / catch

try:
    sched = straight_line_depreciation(y, p, r)
except TypeError as exc:
    if 'Purchase value must be numeric' in str(exc):
        sched = straight_line_depreciation(y, float(p), r)
    else:
        raise

Prevention

When it happens

Trigger: Calling straight_line_depreciation(5, '1250.0', 50.0), passing None for an optional field, or passing a decimal.Decimal from a money library. Fires after the useful_years checks pass.

Common situations: Currency amounts arriving as strings from CSV/JSON/HTML scraping, Decimal from database numeric columns, or None defaults from sparse records.

Related errors


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