Skip to content

Commit

Permalink
Improve math filter doc strings
Browse files Browse the repository at this point in the history
  • Loading branch information
jg-rp committed Mar 24, 2024
1 parent 969a22e commit 36d3c91
Showing 1 changed file with 33 additions and 43 deletions.
76 changes: 33 additions & 43 deletions liquid/builtin/filters/math.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,51 +10,44 @@
from liquid.filter import math_filter
from liquid.filter import num_arg

DecimalT = decimal.Decimal
NumberT = Union[float, int]
# TODO: [VERSION_2] Either handle all filter function argument type conversions
# in a decorator or all in the function itself. Having these type conversions
# split between decorators and calls to helper functions does not help with
# readability, or make it easy to write good doc strings.


@math_filter
def abs_(num: NumberT) -> NumberT:
"""Return the absolute value of a number.
Accepts an int, float or a string representations of an int or float.
"""
def abs_(num: Union[float, int]) -> Union[float, int]:
"""Return the absolute value of number _num_."""
return abs(num)


@math_filter
def at_most(num: NumberT, other: NumberT) -> NumberT:
"""Return `val` or `args[0]`, whichever is smaller.
Accepts an int, float or a string representations of an int or float.
"""
def at_most(num: Union[float, int], other: Union[float, int]) -> Union[float, int]:
"""Return _val_ or _other_, whichever is smaller."""
other = num_arg(other, default=0)
return min(num, other)


@math_filter
def at_least(num: NumberT, other: NumberT) -> NumberT:
"""Return `val` or `args[0]`, whichever is greater.
Accepts an int, float or a string representations of an int or float.
"""
def at_least(num: Union[float, int], other: Union[float, int]) -> Union[float, int]:
"""Return _val_ or _other_, whichever is greater."""
other = num_arg(other, default=0)
return max(num, other)


@math_filter
def ceil(num: NumberT) -> NumberT:
"""Return the ceiling of x as an Integral.
Accepts an int, float or a string representations of an int or float.
"""
def ceil(num: Union[float, int]) -> Union[float, int]:
"""Return _num_ rounded up to the next integer."""
return math.ceil(num)


@math_filter
def divided_by(num: NumberT, other: object) -> NumberT:
"""Divide `num` by `other`."""
def divided_by(num: Union[float, int], other: object) -> Union[float, int]:
"""Return the result of dividing _num_ by _other_.
If both _num_ and _other_ are integers, integer division is performed.
"""
other = num_arg(other, default=0)

try:
Expand All @@ -66,37 +59,34 @@ def divided_by(num: NumberT, other: object) -> NumberT:


@math_filter
def floor(num: NumberT) -> NumberT:
"""Return the floor of x as an Integral.
Accepts an int, float or a string representations of an int or float.
"""
def floor(num: Union[float, int]) -> Union[float, int]:
"""Return _num_ rounded down to the next integer."""
return math.floor(num)


@math_filter
def minus(num: NumberT, other: NumberT) -> NumberT:
"""Subtract one number from another."""
def minus(num: Union[float, int], other: Union[float, int]) -> Union[float, int]:
"""Return the result of subtracting _other_ from _num_."""
other = num_arg(other, default=0)

if isinstance(num, int) and isinstance(other, int):
return num - other
return float(DecimalT(str(num)) - DecimalT(str(other)))
return float(decimal.Decimal(str(num)) - decimal.Decimal(str(other)))


@math_filter
def plus(num: NumberT, other: NumberT) -> NumberT:
"""Add one number to another."""
def plus(num: Union[float, int], other: Union[float, int]) -> Union[float, int]:
"""Return the result of adding _other_ to _num_."""
other = num_arg(other, default=0)

if isinstance(num, int) and isinstance(other, int):
return num + other
return float(DecimalT(str(num)) + DecimalT(str(other)))
return float(decimal.Decimal(str(num)) + decimal.Decimal(str(other)))


@math_filter
def round_(num: NumberT, ndigits: Optional[int] = None) -> NumberT:
"""Round a number to a given precision in decimal digits."""
def round_(num: Union[float, int], ndigits: Optional[int] = None) -> Union[float, int]:
"""Returns the result of rounding _num_ to _ndigits_ decimal digits."""
if ndigits is None or is_undefined(ndigits):
return round(num)

Expand All @@ -118,24 +108,24 @@ def round_(num: NumberT, ndigits: Optional[int] = None) -> NumberT:


@math_filter
def times(num: NumberT, other: NumberT) -> NumberT:
"""Multiply a value by an integer or float."""
def times(num: Union[float, int], other: Union[float, int]) -> Union[float, int]:
"""Return the result of multiplying _num_ by _other_."""
other = num_arg(other, default=0)

if isinstance(num, int) and isinstance(other, int):
return num * other
return float(DecimalT(str(num)) * DecimalT(str(other)))
return float(decimal.Decimal(str(num)) * decimal.Decimal(str(other)))


@math_filter
def modulo(num: NumberT, other: NumberT) -> NumberT:
"""Divide a value by a number and returns the remainder."""
def modulo(num: Union[float, int], other: Union[float, int]) -> Union[float, int]:
"""Return the remainder of dividing _num_ by _other_."""
other = num_arg(other, default=0)

try:
if isinstance(num, int) and isinstance(other, int):
return num % other
return float(DecimalT(str(num)) % DecimalT(str(other)))
return float(decimal.Decimal(str(num)) % decimal.Decimal(str(other)))

except ZeroDivisionError as err:
raise FilterArgumentError(f"modulo: can't divide by {other}") from err

0 comments on commit 36d3c91

Please sign in to comment.