Repository: joke2k/faker (Python)

Issue:
Why does faker.misc.uuid has `cast_to=str` by default? 
# I'm willing to open PR
should this issue be accepted

* Faker version: latest
* OS: N/A

`faker.misc.uuid` has a arg `cast_to` with `str` as default.  So the returned value is always string.
https://github.com/joke2k/faker/blob/9f48a5c6a251b2b8d9f84f65472f946b85b9a923/faker/providers/misc/__init__.py#L95

I want to have the `uuid.UUID` object returned. 

Calling with `cast_to=UUID` again raises a Error on UUID lib (of course it would). Since it's returned `UUID(UUID([...]))`from faker with this

![image](https://user-images.githubusercontent.com/3301060/80141445-f1113900-857f-11ea-85a2-2252c74acd00.png)

So I would have to cast it like this `UUID(str(UUID([...])))` to be funcional.

### Steps to reproduce

1. `faker.uuid(cast_to=str)`
1. `faker.uuid(cast_to=uuid.UUID)`

### Expected behavior
I should be able to call  `faker.uuid(cast_to=None)` and have the pure `UUID` object returned.

### Actual behavior
Faker forces object `UUID` to be cast.




Discussion:
I agree, we should make it possible to retrieve a full-fledged uuid object.

I would like to keep the default `cast_to=str` in the method's signature for backward-compatibility.

We could just special-case `None`:

```python
uuid_instance = uuid.UUID(...)

if cast_to is not None:
    uuid_instance = cast_to(uuid_instance)
return uuid_instance
```
After working on the PR found how it could be possible without the changes on the tests. Still better to make the None case. I'ts more explicit. With docs added it's perfect.

![image](https://user-images.githubusercontent.com/3301060/80157177-f5e3e600-859b-11ea-90a5-fe60cbe771ec.png)




Patch:
diff --git a/faker/providers/misc/__init__.py b/faker/providers/misc/__init__.py
index c4906eff66..39fb692f02 100644
--- a/faker/providers/misc/__init__.py
+++ b/faker/providers/misc/__init__.py
@@ -87,12 +87,20 @@ def sha256(self, raw_output=False):
         return res.hexdigest()
 
     def uuid4(self, cast_to=str):
-        """Generate a random UUID4 object and cast it to another type using a callable ``cast_to``.
+        """Generate a random UUID4 object and cast it to another type if specified using a callable ``cast_to``.
 
         By default, ``cast_to`` is set to ``str``.
+
+        May be called with ``cast_to=None`` to return a full-fledged ``UUID``.
+
+        :sample:
+        :sample: cast_to=None
         """
         # Based on http://stackoverflow.com/q/41186818
-        return cast_to(uuid.UUID(int=self.generator.random.getrandbits(128), version=4))
+        generated_uuid = uuid.UUID(int=self.generator.random.getrandbits(128), version=4)
+        if cast_to is not None:
+            generated_uuid = cast_to(generated_uuid)
+        return generated_uuid
 
     def password(
             self,


Test patch:
diff --git a/tests/providers/test_misc.py b/tests/providers/test_misc.py
index 16194c2af0..f616db6508 100644
--- a/tests/providers/test_misc.py
+++ b/tests/providers/test_misc.py
@@ -17,7 +17,7 @@ def setUp(self):
         self.fake = Faker()
         Faker.seed(0)
 
-    def test_uuid4(self):
+    def test_uuid4_str(self):
         uuid4 = self.fake.uuid4()
         assert uuid4
         assert isinstance(uuid4, str)
@@ -28,7 +28,7 @@ def test_uuid4_int(self):
         assert isinstance(uuid4, int)
 
     def test_uuid4_uuid_object(self):
-        uuid4 = self.fake.uuid4(cast_to=lambda x: x)
+        uuid4 = self.fake.uuid4(cast_to=None)
         assert uuid4
         assert isinstance(uuid4, uuid.UUID)