Skip to content

Commit

Permalink
Ensure pyfloat honors min and max values (#1826)
Browse files Browse the repository at this point in the history
* fix #1825
  • Loading branch information
mvanderlee authored Apr 4, 2023
1 parent b36152b commit 842c983
Show file tree
Hide file tree
Showing 2 changed files with 40 additions and 9 deletions.
27 changes: 18 additions & 9 deletions faker/providers/python/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -178,20 +178,23 @@ def pyfloat(

sign = ""
if (min_value is not None) or (max_value is not None):
# Copy values to ensure we're not modifying the original values and thus going out of bounds
left_min_value = min_value
left_max_value = max_value
# Make sure left_digits still respected
if left_digits is not None:
if max_value is None:
max_value = 10**left_digits # minus smallest representable, adjusted later
left_max_value = 10**left_digits # minus smallest representable, adjusted later
if min_value is None:
min_value = -(10**left_digits) # plus smallest representable, adjusted later
left_min_value = -(10**left_digits) # plus smallest representable, adjusted later

if max_value is not None and max_value < 0:
max_value += 1 # as the random_int will be generated up to max_value - 1
left_max_value += 1 # as the random_int will be generated up to max_value - 1
if min_value is not None and min_value < 0:
min_value += 1 # as we then append digits after the left_number
left_min_value += 1 # as we then append digits after the left_number
left_number = self._safe_random_int(
min_value,
max_value,
left_min_value,
left_max_value,
positive,
)
else:
Expand All @@ -212,11 +215,17 @@ def pyfloat(
result = min(result, 10**left_digits - 1)
result = max(result, -(10**left_digits + 1))

# It's possible for the result to end up > than max_value
# This is a quick hack to ensure result is always smaller.
# It's possible for the result to end up > than max_value or < than min_value
# When this happens we introduce some variance so we're not always the exactly the min_value or max_value.
# Which can happen a lot depending on the difference of the values.
# Ensure the variance is bound by the difference between the max and min
if max_value is not None:
if result > max_value:
result = result - (result - max_value)
result = result - (result - max_value + self.generator.random.uniform(0, max_value - min_value))
if min_value is not None:
if result < min_value:
result = result + (min_value - result + self.generator.random.uniform(0, max_value - min_value))

return result

def _safe_random_int(self, min_value: float, max_value: float, positive: bool) -> int:
Expand Down
22 changes: 22 additions & 0 deletions tests/providers/test_python.py
Original file line number Diff line number Diff line change
Expand Up @@ -199,6 +199,17 @@ def test_max_value_and_positive(self):
self.assertLessEqual(result, 100)
self.assertGreater(result, 0)

def test_max_and_min_value_positive_with_decimals(self):
"""
Combining the max_value and min_value keyword arguments with
positive values for each produces numbers that obey both of
those constraints.
"""
for _ in range(1000):
result = self.fake.pyfloat(min_value=100.123, max_value=200.321)
self.assertLessEqual(result, 200.321)
self.assertGreaterEqual(result, 100.123)

def test_max_and_min_value_negative(self):
"""
Combining the max_value and min_value keyword arguments with
Expand All @@ -210,6 +221,17 @@ def test_max_and_min_value_negative(self):
self.assertLessEqual(result, -100)
self.assertGreaterEqual(result, -200)

def test_max_and_min_value_negative_with_decimals(self):
"""
Combining the max_value and min_value keyword arguments with
negative values for each produces numbers that obey both of
those constraints.
"""
for _ in range(1000):
result = self.fake.pyfloat(max_value=-100.123, min_value=-200.321)
self.assertLessEqual(result, -100.123)
self.assertGreaterEqual(result, -200.321)

def test_positive_and_min_value_incompatible(self):
"""
An exception should be raised if positive=True is set, but
Expand Down

0 comments on commit 842c983

Please sign in to comment.