MushroomMaula / fastapi_login

FastAPI-Login tries to provide similar functionality as Flask-Login does.
https://pypi.org/project/fastapi-login
MIT License
639 stars 58 forks source link

TypeError: the first argument must be callable #58

Closed qiankunxienb closed 3 years ago

qiankunxienb commented 3 years ago

My program was developed based on fastapi_login==1.6.2

Today, I upgrade fastapi_login to the latest version: 1.7.0. When I login, it raises error.

some of the error code:

2021-09-23 14:58:04 | TypeError: the first argument must be callable
-- | --
  |   | 2021-09-23 14:58:04 | self._user_callback = ordered_partial(callback, *args, **kwargs)
  |   | 2021-09-23 14:58:04 | File "/usr/local/lib/python3.8/site-packages/fastapi_login/fastapi_login.py", line 147, in decorator
  |   | 2021-09-23 14:58:04 | user = load_user(name)

The function user_loader in fastapi_login.py of version 1.6.2 is:

    def user_loader(self, callback: Union[Callable, Awaitable]) -> Union[Callable, Awaitable]:
        self._user_callback = callback
        return callback

However, In the latest version, it becomes to:

def user_loader(self, *args, **kwargs) -> Union[Callable, Awaitable]:
        def decorator(callback: Union[Callable, Awaitable]):
            """
            The actual setter of the load_user callback
            Args:
                callback (Callable or Awaitable): The callback which returns the user
            Returns:
                Partial of the callback with given args and keyword arguments already set
            """
            self._user_callback = ordered_partial(callback, *args, **kwargs)
        return decorator

You add the function ordered_partial here cause my problem. But When I refer to the release note, I did not find any notice for this change, only find a pull request note in #56 . It seems that your code is not backwards compatible. @MushroomMaula

MushroomMaula commented 3 years ago

You are correct, I am sorry this happend. My tests didn't catch it because I didn't use the decorator syntax. For a quick fix you can just add parantheses behind the decorator like this:

@manager.user_loader()
def user_loader(email: str):
     ....

Im working on fixing this.

MushroomMaula commented 3 years ago

However I can't exactly reproduce your error. Please provide an example of the method your decorated with `manager.user_loader and when this exception occurs

okazdal commented 3 years ago
import motor
from config import DEFAULT_SETTINGS
from beanie import init_beanie
from models.user import User
from icecream import ic
import asyncio
from security import manager

async def setup():
    # CREATE MOTOR CLIENT
    client = motor.motor_asyncio.AsyncIOMotorClient(
        DEFAULT_SETTINGS.mongo_dsn
    )

    # INIT BEANIE
    await init_beanie(client.automatik_default, document_models=[User])

@manager.user_loader
async def get_user(email: str) -> User:
    user = await User.find_one(User.email == email)
    ic(user)
    # if user is None:
    #     # raise HTTPException(status_code=404, detail="User not found")
    #     return None
    # return user
    return user

async def main():
    await setup()
    email = 'user@example.com'
    user_exists = await get_user(email)
    ic(user_exists)
    user = await User.find_one(User.email == email)
    ic(user)

if __name__ == '__main__':
    asyncio.run(main())

Code above doesn't work with v1.7.1

It works with v1.6.3

MushroomMaula commented 3 years ago

What errors are you getting?

okazdal commented 3 years ago

Sorry forgot to paste the error..

/home/okazdal/.cache/pypoetry/virtualenvs/sekuritim-auto-selfhosted-Hg4E5aVa-py3.9/lib/python3.9/site-packages/fastapi_login/fastapi_login.py:158: SyntaxWarning: As of version 1.7.0 decorating your callback like this is not recommended anymore.
Please add empty parentheses like this @manager.user_loader() if you don'twhich to pass additional arguments to your callback.
  warnings.warn(SyntaxWarning(
Traceback (most recent call last):
  File "/home/okazdal/PycharmProjects/sekuritim-auto-selfhosted/misc/selfhosted/create_user.py", line 41, in <module>
    asyncio.run(main())
  File "/home/okazdal/py3.9/lib/python3.9/asyncio/runners.py", line 44, in run
    return loop.run_until_complete(main)
  File "/home/okazdal/py3.9/lib/python3.9/asyncio/base_events.py", line 642, in run_until_complete
    return future.result()
  File "/home/okazdal/PycharmProjects/sekuritim-auto-selfhosted/misc/selfhosted/create_user.py", line 34, in main
    user_exists = await get_user(email)
TypeError: 'NoneType' object is not callable
MushroomMaula commented 3 years ago

Thanks I think I know whats the issue

okazdal commented 3 years ago

Error after adding recommended parentheses

Traceback (most recent call last):
  File "/home/okazdal/PycharmProjects/sekuritim-auto-selfhosted/misc/selfhosted/create_user.py", line 41, in <module>
    asyncio.run(main())
  File "/home/okazdal/py3.9/lib/python3.9/asyncio/runners.py", line 44, in run
    return loop.run_until_complete(main)
  File "/home/okazdal/py3.9/lib/python3.9/asyncio/base_events.py", line 642, in run_until_complete
    return future.result()
  File "/home/okazdal/PycharmProjects/sekuritim-auto-selfhosted/misc/selfhosted/create_user.py", line 34, in main
    user_exists = await get_user(email)
TypeError: 'NoneType' object is not callable
MushroomMaula commented 3 years ago

Yeah I think I'm almost finished fixing this. The issuse is that I don't return the method that is given to the decorator.

MushroomMaula commented 3 years ago

I just published a new version that should have fixed this bug. Sorry for the inconvenience.

okazdal commented 3 years ago

v1.7.2 works... Thank you.