Repository: joke2k/faker

Issue:
Enables min and max values for pydecimal
Currently is not possible to set min or max values to `pydecimal` or `pyfloat`. It would be nice if we could pass these parameters.

If it makes senses I can open a PR.


Discussion:
Thank you @Lrcezimbra ! Sounds like a useful addition. Feel free to submit a PR

Resolving patch:
diff --git a/faker/providers/python/__init__.py b/faker/providers/python/__init__.py
--- a/faker/providers/python/__init__.py
+++ b/faker/providers/python/__init__.py
@@ -32,7 +32,9 @@ def pystr(self, min_chars=None, max_chars=20):
                 ),
             )
 
-    def pyfloat(self, left_digits=None, right_digits=None, positive=False):
+    def pyfloat(self, left_digits=None, right_digits=None, positive=False,
+                min_value=None, max_value=None):
+
         if left_digits is not None and left_digits < 0:
             raise ValueError(
                 'A float number cannot have less than 0 digits in its '
@@ -44,6 +46,8 @@ def pyfloat(self, left_digits=None, right_digits=None, positive=False):
         if left_digits == 0 and right_digits == 0:
             raise ValueError(
                 'A float number cannot have less than 0 digits in total')
+        if None not in (min_value, max_value) and min_value > max_value:
+            raise ValueError('Min value cannot be greater than max value')
 
         left_digits = left_digits if left_digits is not None else (
             self.random_int(1, sys.float_info.dig))
@@ -51,16 +55,30 @@ def pyfloat(self, left_digits=None, right_digits=None, positive=False):
             self.random_int(0, sys.float_info.dig - left_digits))
         sign = 1 if positive else self.random_element((-1, 1))
 
+        if (min_value is not None) or (max_value is not None):
+            if min_value is None:
+                min_value = max_value - self.random_int()
+            if max_value is None:
+                max_value = min_value + self.random_int()
+
+            left_number = self.random_int(min_value, max_value)
+        else:
+            left_number = sign * self.random_number(left_digits)
+
         return float("{0}.{1}".format(
-            sign * self.random_number(left_digits),
+            left_number,
             self.random_number(right_digits),
         ))
 
     def pyint(self):
         return self.generator.random_int()
 
-    def pydecimal(self, left_digits=None, right_digits=None, positive=False):
-        return Decimal(str(self.pyfloat(left_digits, right_digits, positive)))
+    def pydecimal(self, left_digits=None, right_digits=None, positive=False,
+                  min_value=None, max_value=None):
+
+        float_ = self.pyfloat(
+            left_digits, right_digits, positive, min_value, max_value)
+        return Decimal(str(float_))
 
     def pytuple(self, nb_elements=10, variable_nb_elements=True, *value_types):
         return tuple(


Test patch:
diff --git a/tests/providers/test_python.py b/tests/providers/test_python.py
new file mode 100644
--- /dev/null
+++ b/tests/providers/test_python.py
@@ -0,0 +1,62 @@
+#  -*- coding: utf-8 -*-
+
+import unittest
+
+from faker import Faker
+
+
+class TestPyfloat(unittest.TestCase):
+    def setUp(self):
+        self.factory = Faker()
+
+    def test_pyfloat(self):
+        result = self.factory.pyfloat()
+
+        self.assertIsInstance(result, float)
+
+    def test_left_digits(self):
+        expected_left_digits = 10
+
+        result = self.factory.pyfloat(left_digits=expected_left_digits)
+
+        left_digits = len(str(abs(int(result))))
+        self.assertGreaterEqual(expected_left_digits, left_digits)
+
+    def test_right_digits(self):
+        expected_right_digits = 10
+
+        result = self.factory.pyfloat(right_digits=expected_right_digits)
+
+        right_digits = len(str(result).split('.')[1])
+        self.assertGreaterEqual(expected_right_digits, right_digits)
+
+    def test_positive(self):
+        result = self.factory.pyfloat(positive=True)
+
+        self.assertGreaterEqual(result, 0)
+        self.assertEqual(result, abs(result))
+
+    def test_min_value(self):
+        min_values = (0, 10, -1000, 1000, 999999)
+
+        for min_value in min_values:
+            result = self.factory.pyfloat(min_value=min_value)
+            self.assertGreaterEqual(result, min_value)
+
+    def test_max_value(self):
+        max_values = (0, 10, -1000, 1000, 999999)
+
+        for max_value in max_values:
+            result = self.factory.pyfloat(max_value=max_value)
+            self.assertLessEqual(result, max_value)
+
+    def test_max_value_should_be_greater_than_min_value(self):
+        """
+        An exception should be raised if min_value is greater than max_value
+        """
+        expected_message = 'Min value cannot be greater than max value'
+        with self.assertRaises(ValueError) as raises:
+            self.factory.pyfloat(min_value=100, max_value=0)
+
+        message = str(raises.exception)
+        self.assertEqual(message, expected_message)