Repository: pydantic/pydantic

Issue:
UUID validation fails when provided with 16-byte string
I'm trying to utilize [fastapi](https://github.com/tiangolo/fastapi) + [sqlalchemy](https://github.com/sqlalchemy) which uses pydantic. My sqlalchemy column type is BINARY(16) mapping to that exact type in a MariaDB/MySQL database:

`uuid = Column(BINARY(16), nullable=False, unique=True)`

In pydantic I'm defining as:

`uuid: UUID`

I get an error thrown that the "value is not a valid uuid (type=type_error.uuid)".

I've cloned pydantic and included a new test for the following:

`('uuid_check', b'\x12\x34\x56\x78' * 4, UUID('12345678-1234-5678-1234-567812345678')),`

...which fails using your current code. You can find the test byte string above in the [official python documentation](https://docs.python.org/3/library/uuid.html). I've made a modification in validators to fallback to utilizing the bytes argument in UUID, and then the tests pass. I'm hoping you'd be interested in this fix, as its currently preventing us from using pydantic for a large project refactor. Thank you.



Discussion:
I might create a subclass of UUID following the [Custom Data Types doc](https://pydantic-docs.helpmanual.io/usage/types/#custom-data-types) to be able to move forward with your project refactor. Something like this should work:
```pycon
In [1]: from uuid import UUID

In [2]: from pydantic import BaseModel

In [3]: class BinaryUUID(UUID):
   ...:     @classmethod
   ...:     def __get_validators__(cls):
   ...:         yield cls.validate
   ...:
   ...:     @classmethod
   ...:     def validate(cls, v):
   ...:         if not isinstance(v, bytes):
   ...:             raise TypeError('bytes required')
   ...:
   ...:         return cls(bytes=v)
   ...:

In [4]: class TestUuid(BaseModel):
   ...:     uuid: UUID
   ...:     buuid: BinaryUUID
   ...:

In [5]: TestUuid(uuid='12345678123456781234567812345678', buuid=b'\x12\x34\x56\x78'*4)
Out[5]: TestUuid(uuid=UUID('12345678-1234-5678-1234-567812345678'), buuid=BinaryUUID('12345678-1234-5678-1234-567812345678'))
```

And if you would like to submit a PR with the fix or post the modification you made here for discussion, that would be welcome.

Resolving patch:
diff --git a/pydantic/validators.py b/pydantic/validators.py
--- a/pydantic/validators.py
+++ b/pydantic/validators.py
@@ -252,7 +252,12 @@ def uuid_validator(v: Any, field: 'ModelField') -> UUID:
         if isinstance(v, str):
             v = UUID(v)
         elif isinstance(v, (bytes, bytearray)):
-            v = UUID(v.decode())
+            try:
+                v = UUID(v.decode())
+            except ValueError:
+                # 16 bytes in big-endian order as the bytes argument fail
+                # the above check
+                v = UUID(bytes=v)
     except ValueError:
         raise errors.UUIDError()
 


Test patch:
diff --git a/tests/test_types.py b/tests/test_types.py
--- a/tests/test_types.py
+++ b/tests/test_types.py
@@ -392,6 +392,7 @@ def __bool__(self) -> bool:
         ('uuid_check', 'ebcdab58-6eb8-46fb-a190-d07a33e9eac8', UUID('ebcdab58-6eb8-46fb-a190-d07a33e9eac8')),
         ('uuid_check', UUID('ebcdab58-6eb8-46fb-a190-d07a33e9eac8'), UUID('ebcdab58-6eb8-46fb-a190-d07a33e9eac8')),
         ('uuid_check', b'ebcdab58-6eb8-46fb-a190-d07a33e9eac8', UUID('ebcdab58-6eb8-46fb-a190-d07a33e9eac8')),
+        ('uuid_check', b'\x12\x34\x56\x78' * 4, UUID('12345678-1234-5678-1234-567812345678')),
         ('uuid_check', 'ebcdab58-6eb8-46fb-a190-', ValidationError),
         ('uuid_check', 123, ValidationError),
         ('decimal_check', 42.24, Decimal('42.24')),