Repository: litestar-org/polyfactory (python)

Issue:
Bug: UUIDBase ID Value Changed from UUID to Bytes
### Description

In the example below, `UserFactory.build().id` outputs a UUID.

When upgrading from version `polyfactory==2.14.1` to `polyfactory==2.15.0`, it is observed that `UserFactory.build().id` now outputs Bytes instead of a UUID.

Is the output in Bytes intended? Am I missing something?


### MCVE

```python
from advanced_alchemy.base import UUIDBase
from polyfactory.factories.sqlalchemy_factory import SQLAlchemyFactory


class User(UUIDBase):
    pass


class UserFactory(SQLAlchemyFactory[User]):
    pass


print("id: ", UserFactory.build().id)
```


### Steps to reproduce

_No response_

### Screenshots

_No response_

### Logs

```bash
# polyfactory==2.14.1
id: 8cb1dff7-5232-48ba-a249-99946e4c13af

# polyfactory==2.15.0
id: b'58'
```


### Release Version

2.15.0

### Platform

- [ ] Linux
- [ ] Mac
- [ ] Windows
- [ ] Other (Please specify in the description above)

<!-- POLAR PLEDGE BADGE START -->
---
> [!NOTE]  
> While we are open for sponsoring on [GitHub Sponsors](https://github.com/sponsors/litestar-org/) and 
> [OpenCollective](https://opencollective.com/litestar), we also utilize [Polar.sh](https://polar.sh/) to engage in pledge-based sponsorship.
>
> Check out all issues funded or available for funding [on our Polar.sh dashboard](https://polar.sh/litestar-org)
> * If you would like to see an issue prioritized, make a pledge towards it!
> * We receive the pledge once the issue is completed & verified
> * This, along with engagement in the community, helps us know which features are a priority to our users.

<a href="https://polar.sh/litestar-org/polyfactory/issues/511">
<picture>
  <source media="(prefers-color-scheme: dark)" srcset="https://polar.sh/api/github/litestar-org/polyfactory/issues/511/pledge.svg?darkmode=1">
  <img alt="Fund with Polar" src="https://polar.sh/api/github/litestar-org/polyfactory/issues/511/pledge.svg">
</picture>
</a>
<!-- POLAR PLEDGE BADGE END -->


Pull request description:
fix: favour SA mapped type over impl type
<!--
By submitting this pull request, you agree to:
- follow [Litestar's Code of Conduct](https://github.com/litestar-org/.github/blob/main/CODE_OF_CONDUCT.md)
- follow [Litestar's contribution guidelines](https://github.com/litestar-org/.github/blob/main/CONTRIBUTING.md)
- follow the [PSFs's Code of Conduct](https://www.python.org/psf/conduct/)
-->

### Pull Request Checklist

- [ ] New code has 100% test coverage
- [ ] (If applicable) The prose documentation has been updated to reflect the changes introduced by this PR
- [ ] (If applicable) The reference documentation has been updated to reflect the changes introduced by this PR
- [ ] Pre-Commit Checks were ran and passed
- [ ] Tests were ran and passed

### Description
<!--
Please describe your pull request for new release changelog purposes
-->

- 

### Close Issue(s)
<!--
Please add in issue numbers this pull request will close, if applicable
Examples: Fixes #4321 or Closes #1234
-->

- Fixes #511 


Patch:
diff --git a/polyfactory/factories/sqlalchemy_factory.py b/polyfactory/factories/sqlalchemy_factory.py
index 62a7c0a..5a2155b 100644
--- a/polyfactory/factories/sqlalchemy_factory.py
+++ b/polyfactory/factories/sqlalchemy_factory.py
@@ -129,11 +129,10 @@ class SQLAlchemyFactory(Generic[T], BaseFactory[T]):
         elif issubclass(column_type, types.ARRAY):
             annotation = List[column.type.item_type.python_type]  # type: ignore[assignment,name-defined]
         else:
-            annotation = (
-                column.type.impl.python_type  # pyright: ignore[reportGeneralTypeIssues]
-                if hasattr(column.type, "impl")
-                else column.type.python_type
-            )
+            try:
+                annotation = column.type.python_type
+            except NotImplementedError:
+                annotation = column.type.impl.python_type  # type: ignore[attr-defined]
 
         if column.nullable:
             annotation = Union[annotation, None]  # type: ignore[assignment]


Test patch:
diff --git a/tests/sqlalchemy_factory/test_sqlalchemy_factory_common.py b/tests/sqlalchemy_factory/test_sqlalchemy_factory_common.py
index 6a7657d..ca77fd1 100644
--- a/tests/sqlalchemy_factory/test_sqlalchemy_factory_common.py
+++ b/tests/sqlalchemy_factory/test_sqlalchemy_factory_common.py
@@ -1,6 +1,7 @@
 from dataclasses import dataclass
 from enum import Enum
-from typing import Any, Callable, Type
+from typing import Any, Callable, Type, Union
+from uuid import UUID
 
 import pytest
 from sqlalchemy import Column, ForeignKey, Integer, String, create_engine, inspect, orm, types
@@ -347,3 +348,37 @@ def test_alias() -> None:
 
     result = ModelFactory.build()
     assert isinstance(result.name, str)
+
+
+@pytest.mark.parametrize("python_type_", (UUID, None))
+def test_sqlalchemy_custom_type_from_type_decorator(python_type_: Union[type, None]) -> None:
+    class CustomType(types.TypeDecorator):
+        impl = types.CHAR(32)
+        cache_ok = True
+
+        if python_type_ is not None:
+
+            @property
+            def python_type(self) -> type:
+                return python_type_
+
+    class Base(metaclass=DeclarativeMeta):
+        __abstract__ = True
+        __allow_unmapped__ = True
+
+        registry = _registry
+        metadata = _registry.metadata
+
+    class Model(Base):
+        __tablename__ = f"model_with_custom_types_{python_type_}"
+
+        id: Any = Column(Integer(), primary_key=True)
+        custom_type: Any = Column(type_=CustomType(), nullable=False)
+
+    class ModelFactory(SQLAlchemyFactory[Model]):
+        __model__ = Model
+
+    instance = ModelFactory.build()
+
+    expected_type = python_type_ if python_type_ is not None else CustomType.impl.python_type
+    assert isinstance(instance.custom_type, expected_type)