Repository: joke2k/faker

Issue:
pyfloat provider with positive=True sometimes returns zero
* Faker version: 5.8.0
* OS: macOS 11.1

Call pyfloat with positive=True, and it will sometimes return a zero. 

### Steps to reproduce

Here's an example:

```
import faker
f=faker.Faker()
are_zero = [f.pyfloat(positive=True, max_value=10)==0 for _ in range(100)]
print(any(are_zero))
```

### Expected behavior

It should always print `False` always. 

### Actual behavior

Sometimes it's `True` with f.pyfloat() returning zero. 



Discussion:
Thank you for the rpeort, @sciencectn !

Would you mind submit a Pull Request?

Sure, I'll give it a shot. 

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
@@ -66,9 +66,9 @@ def pyfloat(self, left_digits=None, right_digits=None, positive=False,
             raise ValueError('Min value cannot be greater than max value')
         if None not in (min_value, max_value) and min_value == max_value:
             raise ValueError('Min and max value cannot be the same')
-        if positive and min_value is not None and min_value < 0:
+        if positive and min_value is not None and min_value <= 0:
             raise ValueError(
-                'Cannot combine positive=True and negative min_value')
+                'Cannot combine positive=True with negative or zero min_value')
 
         left_digits = left_digits if left_digits is not None else (
             self.random_int(1, sys.float_info.dig))
@@ -87,7 +87,10 @@ def pyfloat(self, left_digits=None, right_digits=None, positive=False,
             sign = '+' if positive else self.random_element(('+', '-'))
             left_number = self.random_number(left_digits)
 
-        return float(f'{sign}{left_number}.{self.random_number(right_digits)}')
+        result = float(f'{sign}{left_number}.{self.random_number(right_digits)}')
+        if positive and result == 0:
+            result += sys.float_info.epsilon
+        return result
 
     def _safe_random_int(self, min_value, max_value, positive):
         orig_min_value = min_value


Test patch:
diff --git a/tests/providers/test_python.py b/tests/providers/test_python.py
--- a/tests/providers/test_python.py
+++ b/tests/providers/test_python.py
@@ -63,7 +63,7 @@ def test_right_digits(self):
     def test_positive(self):
         result = self.fake.pyfloat(positive=True)
 
-        self.assertGreaterEqual(result, 0)
+        self.assertGreater(result, 0)
         self.assertEqual(result, abs(result))
 
     def test_min_value(self):
@@ -99,7 +99,7 @@ def test_max_value_and_positive(self):
 
         result = self.fake.pyfloat(positive=True, max_value=100)
         self.assertLessEqual(result, 100)
-        self.assertGreaterEqual(result, 0)
+        self.assertGreater(result, 0)
 
     def test_positive_and_min_value_incompatible(self):
         """
@@ -108,7 +108,7 @@ def test_positive_and_min_value_incompatible(self):
         """
 
         expected_message = (
-            "Cannot combine positive=True and negative min_value"
+            "Cannot combine positive=True with negative or zero min_value"
         )
         with self.assertRaises(ValueError) as raises:
             self.fake.pyfloat(min_value=-100, positive=True)
@@ -116,6 +116,14 @@ def test_positive_and_min_value_incompatible(self):
         message = str(raises.exception)
         self.assertEqual(message, expected_message)
 
+    def test_positive_doesnt_return_zero(self):
+        """
+        Choose the right_digits and max_value so it's guaranteed to return zero,
+        then watch as it doesn't because positive=True
+        """
+        result = self.fake.pyfloat(positive=True, right_digits=0, max_value=1)
+        self.assertGreater(result, 0)
+
 
 class TestPystrFormat(unittest.TestCase):