litestar-org / litestar

Production-ready, Light, Flexible and Extensible ASGI API framework | Effortlessly Build Performant APIs
https://litestar.dev/
MIT License
5.64k stars 382 forks source link

Bug: AttributeError: module 'sqlalchemy.types' has no attribute 'Uuid' #1387

Closed peterschutt closed 1 year ago

peterschutt commented 1 year ago

Description

When using SQLAlchemy 1.4x and starlite.contrib.sqlalchemy_1.plugin.SQLAlchemyPlugin we get the following error on application startup:

  File "/home/peter/PycharmProjects/starlite-hello-world/main.py", line 24, in <module>
    app = Starlite(route_handlers=[hello_world], debug=True, plugins=[SQLAlchemyPlugin()])
          ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/home/peter/PycharmProjects/starlite/starlite/app.py", line 415, in __init__
    self.register(route_handler)
  File "/home/peter/PycharmProjects/starlite/starlite/app.py", line 503, in register
    self._create_handler_signature_model(route_handler=route_handler)
  File "/home/peter/PycharmProjects/starlite/starlite/app.py", line 725, in _create_handler_signature_model
    route_handler.signature_model = create_signature_model(
                                    ^^^^^^^^^^^^^^^^^^^^^^^
  File "/home/peter/PycharmProjects/starlite/starlite/_signature/parsing.py", line 212, in create_signature_model
    parsed_params, return_annotation, field_plugin_mappings, dependency_names = parse_fn_signature(
                                                                                ^^^^^^^^^^^^^^^^^^^
  File "/home/peter/PycharmProjects/starlite/starlite/_signature/parsing.py", line 182, in parse_fn_signature
    parameter.annotation = get_type_annotation_from_plugin(parameter, plugin, field_plugin_mappings)
                           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/home/peter/PycharmProjects/starlite/starlite/_signature/parsing.py", line 123, in get_type_annotation_from_plugin
    pydantic_model = plugin.to_data_container_class(model_class=type_value, parameter_name=parameter.name)
                     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/home/peter/PycharmProjects/starlite/starlite/contrib/sqlalchemy_1/plugin.py", line 380, in to_data_container_class
    field_definitions[name] = (self.get_pydantic_type(column.type), ...)
                               ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/home/peter/PycharmProjects/starlite/starlite/contrib/sqlalchemy_1/plugin.py", line 332, in get_pydantic_type
    provider = self.providers_map[column_type_class]
               ^^^^^^^^^^^^^^^^^^
  File "/home/peter/PycharmProjects/starlite/starlite/contrib/sqlalchemy_1/plugin.py", line 226, in providers_map
    sqlalchemy_type.Uuid: lambda x: UUID,
    ^^^^^^^^^^^^^^^^^^^^
AttributeError: module 'sqlalchemy.types' has no attribute 'Uuid'

URL to code causing the issue

No response

MCVE

"""Minimal Starlite application."""
from typing import Any

from sqlalchemy import Column, Integer
from sqlalchemy.orm import declarative_base
from starlite import Request, Starlite, get
from starlite.contrib.sqlalchemy_1.plugin import SQLAlchemyPlugin

Base = declarative_base()

class User(Base):
    __tablename__ = "users"
    id = Column(Integer, primary_key=True)

@get("/")
def hello_world(request: Request[User, Any, Any]) -> dict[str, Any]:
    """Route Handler that outputs hello world."""
    print(f"{request = }")
    return {"hello": "world"}

app = Starlite(route_handlers=[hello_world], debug=True, plugins=[SQLAlchemyPlugin()])

Steps to reproduce

1. run the above code with SQLAlchemy 1.x installed.

Screenshots

"![SCREENSHOT_DESCRIPTION](SCREENSHOT_LINK.png)"

Logs

Traceback (most recent call last):
  File "/home/peter/.pyenv/versions/3.11.0/lib/python3.11/multiprocessing/process.py", line 314, in _bootstrap
    self.run()
  File "/home/peter/.pyenv/versions/3.11.0/lib/python3.11/multiprocessing/process.py", line 108, in run
    self._target(*self._args, **self._kwargs)
  File "/home/peter/.cache/pypoetry/virtualenvs/starlite-hello-world-nPMVAxaQ-py3.11/lib/python3.11/site-packages/uvicorn/_subprocess.py", line 76, in subprocess_started
    target(sockets=sockets)
  File "/home/peter/.cache/pypoetry/virtualenvs/starlite-hello-world-nPMVAxaQ-py3.11/lib/python3.11/site-packages/uvicorn/server.py", line 59, in run
    return asyncio.run(self.serve(sockets=sockets))
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/home/peter/.pyenv/versions/3.11.0/lib/python3.11/asyncio/runners.py", line 190, in run
    return runner.run(main)
           ^^^^^^^^^^^^^^^^
  File "/home/peter/.pyenv/versions/3.11.0/lib/python3.11/asyncio/runners.py", line 118, in run
    return self._loop.run_until_complete(task)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/home/peter/.pyenv/versions/3.11.0/lib/python3.11/asyncio/base_events.py", line 650, in run_until_complete
    return future.result()
           ^^^^^^^^^^^^^^^
  File "/home/peter/.cache/pypoetry/virtualenvs/starlite-hello-world-nPMVAxaQ-py3.11/lib/python3.11/site-packages/uvicorn/server.py", line 66, in serve
    config.load()
  File "/home/peter/.cache/pypoetry/virtualenvs/starlite-hello-world-nPMVAxaQ-py3.11/lib/python3.11/site-packages/uvicorn/config.py", line 471, in load
    self.loaded_app = import_from_string(self.app)
                      ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/home/peter/.cache/pypoetry/virtualenvs/starlite-hello-world-nPMVAxaQ-py3.11/lib/python3.11/site-packages/uvicorn/importer.py", line 21, in import_from_string
    module = importlib.import_module(module_str)
             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/home/peter/.pyenv/versions/3.11.0/lib/python3.11/importlib/__init__.py", line 126, in import_module
    return _bootstrap._gcd_import(name[level:], package, level)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "<frozen importlib._bootstrap>", line 1206, in _gcd_import
  File "<frozen importlib._bootstrap>", line 1178, in _find_and_load
  File "<frozen importlib._bootstrap>", line 1149, in _find_and_load_unlocked
  File "<frozen importlib._bootstrap>", line 690, in _load_unlocked
  File "<frozen importlib._bootstrap_external>", line 940, in exec_module
  File "<frozen importlib._bootstrap>", line 241, in _call_with_frames_removed
  File "/home/peter/PycharmProjects/starlite-hello-world/main.py", line 24, in <module>
    app = Starlite(route_handlers=[hello_world], debug=True, plugins=[SQLAlchemyPlugin()])
          ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/home/peter/PycharmProjects/starlite/starlite/app.py", line 415, in __init__
    self.register(route_handler)
  File "/home/peter/PycharmProjects/starlite/starlite/app.py", line 503, in register
    self._create_handler_signature_model(route_handler=route_handler)
  File "/home/peter/PycharmProjects/starlite/starlite/app.py", line 725, in _create_handler_signature_model
    route_handler.signature_model = create_signature_model(
                                    ^^^^^^^^^^^^^^^^^^^^^^^
  File "/home/peter/PycharmProjects/starlite/starlite/_signature/parsing.py", line 212, in create_signature_model
    parsed_params, return_annotation, field_plugin_mappings, dependency_names = parse_fn_signature(
                                                                                ^^^^^^^^^^^^^^^^^^^
  File "/home/peter/PycharmProjects/starlite/starlite/_signature/parsing.py", line 182, in parse_fn_signature
    parameter.annotation = get_type_annotation_from_plugin(parameter, plugin, field_plugin_mappings)
                           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/home/peter/PycharmProjects/starlite/starlite/_signature/parsing.py", line 123, in get_type_annotation_from_plugin
    pydantic_model = plugin.to_data_container_class(model_class=type_value, parameter_name=parameter.name)
                     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/home/peter/PycharmProjects/starlite/starlite/contrib/sqlalchemy_1/plugin.py", line 380, in to_data_container_class
    field_definitions[name] = (self.get_pydantic_type(column.type), ...)
                               ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/home/peter/PycharmProjects/starlite/starlite/contrib/sqlalchemy_1/plugin.py", line 332, in get_pydantic_type
    provider = self.providers_map[column_type_class]
               ^^^^^^^^^^^^^^^^^^
  File "/home/peter/PycharmProjects/starlite/starlite/contrib/sqlalchemy_1/plugin.py", line 226, in providers_map
    sqlalchemy_type.Uuid: lambda x: UUID,
    ^^^^^^^^^^^^^^^^^^^^
AttributeError: module 'sqlalchemy.types' has no attribute 'Uuid'

Starlite Version

main branch

Platform


[!NOTE]
While we are open for sponsoring on GitHub Sponsors and OpenCollective, we also utilize Polar.sh to engage in pledge-based sponsorship.

Check out all issues funded or available for funding on our Polar.sh dashboard

  • 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.

Fund with Polar

peterschutt commented 1 year ago

I think we should revert that commit from main as the 2.x usage is meant to be covered by the sqlalchemy plugin that is currently only in the dto-refactor branch, and doesn't rely on the provider map.

peterschutt commented 1 year ago

I'll make a separate PR into main for the SQLAlchemy 2.0 plugin stuff..

provinzkraut commented 1 year ago

I think we should revert that commit from main as the 2.x usage is meant to be covered by the sqlalchemy plugin that is currently only in the dto-refactor branch, and doesn't rely on the provider map.

Sounds good

peterschutt commented 1 year ago

Waiting for #1395 before I do this, so there is a viable alternative for sqla 2.0 users.