pymssql might support native UUID, set attribute

Describe the bug

Hi,

We are currently in the process of moving from SQLAlchemy 1.4 to 2.0. We were using UUID type from sqlalchemy-utils. As there is a uuid type in sqlalchemy 2.0, I tried to use it.

Insert works well and the db is up to date, but I encounter an issue while doing a select base on that id. (same error as this one: #7225) .

Documentation suggest that it supports vendor specific uuid types, so I guessed this should work as well.

It doesn't look like a migration issue, as I was able to reproduce the problem with a new table using new code.

Any suggestion is welcomed :)

Thanks,
Simon.

Optional link from https://docs.sqlalchemy.org which documents the behavior that is expected

https://docs.sqlalchemy.org/en/20/core/type_basics.html#sqlalchemy.types.Uuid

SQLAlchemy Version in Use

2.0.4

DBAPI (i.e. the database driver)

pymysql

Database Vendor and Major Version

ms sql 14.0.2042.3 Enterprise Edition (64-bit) Windows Server 2016 Standard 10.0

Python Version

3.10

Operating system

WSL + docker on windows.

To Reproduce

from uuid import uuid4
from sqlalchemy import Column, Integer, Uuid, create_engine, select
from sqlalchemy.orm import declarative_base, Session


Base = declarative_base()

class Estimation(Base):
    """Stats about a translation task."""

    __tablename__ = "test_table"
    id = Column(Uuid(native_uuid=True), primary_key=True)
    score = Column(Integer)


engine = create_engine("mssql+pymssql://[my-url]")

Base.metadata.create_all(engine)
my_id = uuid4()
with Session(engine) as session:
    estimation = Estimation(id=my_id)
    session.add(estimation)
    session.commit()

with Session(engine) as session:
    stmt = select(Estimation).where(Estimation.id==my_id)
    estimation = session.execute(stmt).first()
    print(estimation)
    estimation.score = 5
    session.add(estimation)
    session.commit()

Error

Traceback (most recent call last):
  File "/mnt/c/projects/mtme/sql.py", line 27, in <module>
    estimation = session.execute(stmt).first()
  File "/home/lorensi/miniconda3/envs/lorensi/lib/python3.10/site-packages/sqlalchemy/engine/result.py", line 1397, in first
    return self._only_one_row(
  File "/home/lorensi/miniconda3/envs/lorensi/lib/python3.10/site-packages/sqlalchemy/engine/result.py", line 732, in _only_one_row
    row: Optional[_InterimRowType[Any]] = onerow(hard_close=True)
  File "/home/lorensi/miniconda3/envs/lorensi/lib/python3.10/site-packages/sqlalchemy/engine/result.py", line 2252, in _fetchone_impl
    row = next(self.iterator, _NO_ROW)
  File "/home/lorensi/miniconda3/envs/lorensi/lib/python3.10/site-packages/sqlalchemy/orm/loading.py", line 190, in chunks
    fetch = cursor._raw_all_rows()
  File "/home/lorensi/miniconda3/envs/lorensi/lib/python3.10/site-packages/sqlalchemy/engine/result.py", line 521, in _raw_all_rows
    return [make_row(row) for row in rows]
  File "/home/lorensi/miniconda3/envs/lorensi/lib/python3.10/site-packages/sqlalchemy/engine/result.py", line 521, in <listcomp>
    return [make_row(row) for row in rows]
  File "lib/sqlalchemy/cyextension/resultproxy.pyx", line 24, in sqlalchemy.cyextension.resultproxy.BaseRow.__init__
  File "/home/lorensi/miniconda3/envs/lorensi/lib/python3.10/site-packages/sqlalchemy/sql/sqltypes.py", line 3633, in process
    value = _python_UUID(value)
  File "/home/lorensi/miniconda3/envs/lorensi/lib/python3.10/uuid.py", line 174, in __init__
    hex = hex.replace('urn:', '').replace('uuid:', '')
AttributeError: 'UUID' object has no attribute 'replace'

Additional context

No response