Numeric#

Numeric assertion helpers for approximate comparisons and checks.

Provides the approx class (inspired by pytest.approx) for directional tolerance-based numeric comparisons, plus standalone helpers like isclose, isnan, isinfinite, and percentage.

The approx class supports natural Python comparison syntax with directional (one-sided) tolerance:

  • x == approx(expected); approximately equal (bidirectional tolerance)

  • x > approx(threshold); strictly greater than (tolerance extends below)

  • x >= approx(threshold); at least the threshold (tolerance extends below)

  • x < approx(threshold); strictly less than (tolerance extends above)

  • x <= approx(threshold); at most the threshold (tolerance extends above)

Example#

from punit.assertions.numeric import approx, isclose, isnan

assert 0.1 + 0.2 == approx(0.3)
assert isclose(1 + 2j, 1.0 + 2.0j)
assert not isclose(3, 3.000000001)
assert isnan(float('nan'))
class approx(expected=0, rel_tol=1e-09, abs_tol=0.0)#

Bases: object

Wrapper for approximate comparisons using ==, <, >, etc.

Enables natural Python syntax like 0.1 + 0.2 == approx(0.3). Supports chained methods for range/inequality checks:

x == approx(expected) – approximately equal (default expected=0) x == approx(threshold).greater_than() – >= threshold (one-sided tol below) x == approx(threshold).less_than() – <= threshold (one-sided tol above) x == approx(threshold).at_least() – at least the threshold (one-sided tol below) x == approx(threshold).at_most() – at most the threshold (one-sided tol above) x == approx(threshold).strict_greater_than() – > threshold (tolerance above only) x == approx(threshold).strict_less_than() – < threshold (tolerance below only) x == approx().in_range(lower, upper) – within [lower, upper] with directional tol x == approx().zero() – approximately zero

Parameters:
  • expected (float | int | complex) – The expected numeric value (default 0 for zero-checks).

  • rel_tol (float) – Relative tolerance (default 1e-9).

  • abs_tol (float) – Absolute tolerance (default 0.0).

Create an approx instance with the given expected value and tolerances.

greater_than()#

Return a comparator for >= expected checks (one-sided tolerance below).

Return type:

GreaterThanComparator

less_than()#

Return a comparator for <= expected checks (one-sided tolerance above).

Return type:

LessThanComparator

at_least()#

Return a comparator for >= expected inclusive boundary checks (one-sided tol below).

Return type:

AtLeastComparator

at_most()#

Return a comparator for <= expected inclusive boundary checks (one-sided tol above).

Return type:

AtMostComparator

strict_greater_than()#

Return a StrictGreaterThanComparator for strictly > expected (one-sided tolerance above).

Return type:

StrictGreaterThanComparator

strict_less_than()#

Return a StrictLessThanComparator for strictly < expected (one-sided tolerance below).

Return type:

StrictLessThanComparator

in_range(min_val, max_val)#

Return a comparator for [min_val, max_val] range checks with directional tolerance.

Return type:

ApproxRangeComparator

zero()#

Return a comparator for approximate zero checks.

Return type:

ZeroComparator

isnan(value)#

Check if value is NaN (Not a Number).

For complex inputs, returns True only if both the real and imaginary parts are NaN.

Return type:

bool

Args:

value: The numeric value to check.

Returns:

True if value is NaN, False otherwise.

Example#

from punit.assertions.numeric import isnan

assert isnan(float('nan'))
assert not isnan(0.0)
isinfinite(value)#

Check if value is infinite (positive or negative).

For complex inputs, returns True only if either the real or imaginary part is infinite.

Return type:

bool

Args:

value: The numeric value to check.

Returns:

True if value is infinite, False otherwise.

Example#

from punit.assertions.numeric import isinfinite

assert isinfinite(float('inf'))
assert not isinfinite(0.0)
isclose(a, b, *, rel_tol=1e-09, abs_tol=0.0)#

Check if two numeric values are approximately equal within tolerance.

A drop-in math.isclose replacement that accepts the full Numeric type (float | int | complex). For real inputs the stdlib is used directly; for complex inputs the real and imaginary parts are compared independently using the same tolerances.

Return type:

bool

Args:

a: First numeric value. b: Second numeric value. rel_tol: Relative tolerance (default 1e-9). abs_tol: Absolute tolerance (default 0.0).

Returns:

True if |a - b| <= max(rel_tol * |b|, abs_tol) for real values, or equivalent per-component comparison for complex.

Example#

from punit.assertions.numeric import isclose

assert isclose(1 + 2j, 1.0 + 2.0j)
assert not isclose(3, 3.000000001)
assert isclose(3, 3.000000001, rel_tol=1e-6)
percentage(value_a, value_b, relative_to_expected=True)#

Calculate the percentage difference between two numeric values.

When relative_to_expected=True, uses value_b as reference:

abs(a - b) / |b| * 100

When relative_to_expected=False, uses symmetric form:

abs(a - b) / ((|a| + |b|) / 2) * 100

For complex inputs, magnitudes (abs()) are used consistently: the numerator is the magnitude of the difference, and the denominator is the magnitude of the reference.

Return type:

float

Args:

value_a: The first numeric value. value_b: The second numeric value (reference when relative_to_expected=True). relative_to_expected: If True, use value_b as reference (default).

Returns:

The percentage difference as a float. Returns inf if both values are zero but differ, otherwise 0.0.

Example#

from punit.assertions.numeric import percentage

assert percentage(10, 100) == 90.0
assert percentage(0, 0) == 0.0