Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Obtaining TypeError: Cannot pickle 'module' object on models with many-to-many relationships #540

Open
8 tasks done
Magnaillusion opened this issue Jan 27, 2023 · 2 comments
Labels
question Further information is requested

Comments

@Magnaillusion
Copy link

First Check

  • I added a very descriptive title to this issue.
  • I used the GitHub search to find a similar issue and didn't find it.
  • I searched the SQLModel documentation, with the integrated search.
  • I already searched in Google "How to X in SQLModel" and didn't find any information.
  • I already read and followed all the tutorial in the docs and didn't find an answer.
  • I already checked if it is not related to SQLModel but to Pydantic.
  • I already checked if it is not related to SQLModel but to SQLAlchemy.

Commit to Help

  • I commit to help with one of those options 👆

Example Code

# NOTE: all of these classes are contained in separate files. They've been compiled into this list for convenience

from sqlmodel import SQLModel, Field
from typing import List, Optional
from sqlmodel import Field, Relationship
from sqlalchemy import UniqueConstraint


class ManufacturerPerUser(SQLModel, table=True):
    __tablename__ = 'manufacturer_per_users'
    id: Optional[int] = Field(primary_key=True, nullable=False)

    user_id: Optional[int] = Field(
        default=None,
        nullable=False,
        foreign_key='User.id'
    )

    manufacturer_id: Optional[int] = Field(
        default=None,
        nullable=False,
        foreign_key='Manufacturer.id'
    )


class ManufacturerBase(SQLModel):
    pass # snipping out extraneous fields


class Manufacturer(ManufacturerBase, table=True):
    __tablename__ = 'manufacturers'
    id: Optional[int] = Field(primary_key=True, nullable=False)
    
    users: List['Users'] = Relationship(
        back_populates='manufacturers', 
        link_model=ManufacturerPerUser,
        sa_relationship_kwargs={'lazy': 'selectin'}
    )


class UserBase(SQLModel):
    sub: str
    pass # snipping out extraneous fields


class User(UserBase, table=True):
    __tablename__ = 'users'
    __table_args__ = (UniqueConstraint('sub'),)
    id: Optional[int] = Field(primary_key=True, nullable=False)

    manufacturers: List['Manufacturer'] = Relationship(
        back_populates='users',
        link_model=ManufacturerPerUser,
        sa_relationship_kwargs={'lazy': 'selectin'}
    )

Description

I upgraded a project to SQLModel version 0.0.8 and, after that, it started giving out TypeError: cannot pickle 'module' object on the models that had a many to many relationship through the link_model Relationship attribute.

I figured it was the many to many relationship since, after I deleted it from one of the models to test, that particular model stopped erroring out. However, there might be something else I'm missing that's causing the error. Either way, the error seems to happen only when there's a Relationship attribute with a link_model for the many to many relation. I even tried to remove the __tablename__ attributes on the tables just in case that was messing something up, but I had no luck.

I tried googling the issue and could not find any solution that would help on any front, so I'm currently at a loss. Closest match was a question where the OP was using SQLAlchemy directly, which I am NOT doing and so the solution proposed did not work for me. Any advice or guidance would be appreciated.

If it helps, I followed this example for the layout (though using PDM instead of Poetry): https://github.com/jonra1993/fastapi-alembic-sqlmodel-async.

Also, note that, before the upgrade to 0.0.8 (we were on 0.0.6 before), the Relationship attributes were completely non-functional, so they didn't error out (we did the joins manually to obtain the data).

The full error dump looks as such:

Traceback (most recent call last):
  File "/Library/Frameworks/Python.framework/Versions/3.11/lib/python3.11/multiprocessing/process.py", line 314, in _bootstrap
    self.run()
  File "/Library/Frameworks/Python.framework/Versions/3.11/lib/python3.11/multiprocessing/process.py", line 108, in run
    self._target(*self._args, **self._kwargs)
  File "/Users/magnaillusion/Development/SEA/new-system/sea-new-backend/.venv/lib/python3.11/site-packages/uvicorn/_subprocess.py", line 76, in subprocess_started
    target(sockets=sockets)
  File "/Users/magnaillusion/Development/SEA/new-system/sea-new-backend/.venv/lib/python3.11/site-packages/uvicorn/server.py", line 60, in run
    return asyncio.run(self.serve(sockets=sockets))
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/Library/Frameworks/Python.framework/Versions/3.11/lib/python3.11/asyncio/runners.py", line 190, in run
    return runner.run(main)
           ^^^^^^^^^^^^^^^^
  File "/Library/Frameworks/Python.framework/Versions/3.11/lib/python3.11/asyncio/runners.py", line 118, in run
    return self._loop.run_until_complete(task)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "uvloop/loop.pyx", line 1517, in uvloop.loop.Loop.run_until_complete
  File "/Users/magnaillusion/Development/SEA/new-system/sea-new-backend/.venv/lib/python3.11/site-packages/uvicorn/server.py", line 67, in serve
    config.load()
  File "/Users/magnaillusion/Development/SEA/new-system/sea-new-backend/.venv/lib/python3.11/site-packages/uvicorn/config.py", line 477, in load
    self.loaded_app = import_from_string(self.app)
                      ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/Users/magnaillusion/Development/SEA/new-system/sea-new-backend/.venv/lib/python3.11/site-packages/uvicorn/importer.py", line 21, in import_from_string
    module = importlib.import_module(module_str)
             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/Library/Frameworks/Python.framework/Versions/3.11/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 "/Users/magnaillusion/Development/SEA/new-system/sea-new-backend/main.py", line 3, in <module>
    from v1 import router as main_router
  File "/Users/magnaillusion/Development/SEA/new-system/sea-new-backend/v1/__init__.py", line 1, in <module>
    from .main_router import router
  File "/Users/magnaillusion/Development/SEA/new-system/sea-new-backend/v1/main_router.py", line 3, in <module>
    from .users import router as users_router
  File "/Users/magnaillusion/Development/SEA/new-system/sea-new-backend/v1/users/__init__.py", line 1, in <module>
    from .router import router
  File "/Users/magnaillusion/Development/SEA/new-system/sea-new-backend/v1/users/router.py", line 2, in <module>
    from .insert_user import insert_user
  File "/Users/magnaillusion/Development/SEA/new-system/sea-new-backend/v1/users/insert_user.py", line 4, in <module>
    from core.db.models import User
  File "/Users/magnaillusion/Development/SEA/new-system/sea-new-backend/core/db/models/__init__.py", line 1, in <module>
    from .User import User
  File "/Users/magnaillusion/Development/SEA/new-system/sea-new-backend/core/db/models/User.py", line 8, in <module>
    class User(UserBase, table=True):
  File "/Users/magnaillusion/Development/SEA/new-system/sea-new-backend/.venv/lib/python3.11/site-packages/sqlmodel/main.py", line 337, in __init__
    temp_field = ModelField.infer(
                 ^^^^^^^^^^^^^^^^^
  File "pydantic/fields.py", line 506, in pydantic.fields.ModelField.infer
  File "pydantic/fields.py", line 436, in pydantic.fields.ModelField.__init__
  File "pydantic/fields.py", line 546, in pydantic.fields.ModelField.prepare
  File "pydantic/fields.py", line 570, in pydantic.fields.ModelField._set_default_and_type
  File "pydantic/fields.py", line 439, in pydantic.fields.ModelField.get_default
  File "pydantic/utils.py", line 695, in pydantic.utils.smart_deepcopy
  File "/Library/Frameworks/Python.framework/Versions/3.11/lib/python3.11/copy.py", line 172, in deepcopy
    y = _reconstruct(x, memo, *rv)
        ^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/Library/Frameworks/Python.framework/Versions/3.11/lib/python3.11/copy.py", line 271, in _reconstruct
    state = deepcopy(state, memo)
            ^^^^^^^^^^^^^^^^^^^^^
  File "/Library/Frameworks/Python.framework/Versions/3.11/lib/python3.11/copy.py", line 146, in deepcopy
    y = copier(x, memo)
        ^^^^^^^^^^^^^^^
  File "/Library/Frameworks/Python.framework/Versions/3.11/lib/python3.11/copy.py", line 231, in _deepcopy_dict
    y[deepcopy(key, memo)] = deepcopy(value, memo)
                             ^^^^^^^^^^^^^^^^^^^^^
  File "/Library/Frameworks/Python.framework/Versions/3.11/lib/python3.11/copy.py", line 161, in deepcopy
    rv = reductor(4)
         ^^^^^^^^^^^
TypeError: cannot pickle 'module' object```

### Operating System

macOS

### Operating System Details

Currently running Montery, M1 chipset.

### SQLModel Version

0.0.8

### Python Version

3.11.1

### Additional Context

_No response_
@Magnaillusion Magnaillusion added the question Further information is requested label Jan 27, 2023
@oktavlachs
Copy link

Same issue observed today when adding an SQLModel to FastAPIs response_model parameter in the HTTP route signature.

@andreandrade141
Copy link

Been having the same issue while using a Simple SqlAlchemy class to represent the user:
def read_users_me( current_user: Annotated[User, Depends(get_current_active_user)] ):

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
question Further information is requested
Projects
None yet
Development

No branches or pull requests

3 participants