Skip to content

AttributeError: '_AsyncGeneratorContextManager' object has no attribute 'execute' #94

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

Closed
aryaniyaps opened this issue Dec 13, 2023 · 5 comments

Comments

@aryaniyaps
Copy link

These are my dependencies:

from contextlib import asynccontextmanager, contextmanager
from typing import AsyncIterator, Iterator

import inject
from argon2 import PasswordHasher
from redis.asyncio import Redis, from_url
from sqlalchemy.ext.asyncio import AsyncConnection

from app.config import settings
from app.core.database import engine
from app.core.emails import EmailSender


@asynccontextmanager
async def get_database_connection() -> AsyncIterator[AsyncConnection]:
    """Get a database connection."""
    async with engine.begin() as connection:
        yield connection


@asynccontextmanager
async def get_redis_client() -> AsyncIterator[Redis]:
    """Get the redis client."""
    redis_client = from_url(
        url=str(settings.redis_url),
    )
    yield redis_client

    await redis_client.aclose()


@contextmanager
def get_email_sender() -> Iterator[EmailSender]:
    """Get the email sender."""
    email_sender = EmailSender(
        email_server=settings.email_server,
        email_from=settings.email_from,
    )
    yield email_sender
    email_sender.close_connection()


def app_config(binder: inject.Binder) -> None:
    """Configure dependencies for the binder."""
    binder.bind_to_constructor(
        EmailSender,
        get_email_sender,
    )
    binder.bind_to_constructor(
        Redis,
        get_redis_client,
    )
    binder.bind_to_provider(
        AsyncConnection,
        get_database_connection,
    )
    binder.bind(
        PasswordHasher,
        PasswordHasher(),
    )


inject.configure(app_config)

This is my UserRepo:

class UserRepo:
    _connection = inject.attr(AsyncConnection)
    _password_hasher = inject.attr(PasswordHasher)

    async def create_user(
        self,
        username: str,
        email: str,
        password: str,
    ) -> User:
        """Create a new user."""
        result = await self._connection.execute(
            insert(users_table)
            .values(
                username=username,
                email=email,
                # hash the password before storing
                password_hash=self.hash_password(
                    password=password,
                ),
            )
            .returning(*users_table.c),
        )
        user_row = result.one()
        return User.model_validate(user_row)

    def hash_password(self, password: str) -> str:
        """Hash the given password."""
        return self._password_hasher.hash(
            password=password,
        )

I am getting this error while accessing the UserRepo:

self = <app.users.repos.UserRepo object at 0x0000016D0F176810>, username = 'new_user', email = 'new@example.com', password = 'password'

    async def create_user(
        self,
        username: str,
        email: str,
        password: str,
    ) -> User:
        """Create a new user."""
>       result = await self._connection.execute(
            insert(users_table)
            .values(
                username=username,
                email=email,
                # hash the password before storing
                password_hash=self.hash_password(
                    password=password,
                ),
            )
            .returning(*users_table.c),
        )
E       AttributeError: '_AsyncGeneratorContextManager' object has no attribute 'execute'

app\users\repos.py:24: AttributeError

This UserRepo is used by a AuthService:

class AuthService:
    _auth_repo = inject.attr(AuthRepo)
    _user_repo = inject.attr(UserRepo)
    _password_hasher = inject.attr(PasswordHasher)

Which is accessed by my falcon resources like this:

class AuthResource:
    @inject.autoparams("auth_service")
    async def on_post_register(
        self,
        req: Request,
        resp: Response,
        auth_service: AuthService,
    ) -> None:
        """Register a new user."""
        data = await req.media
        result = await auth_service.register_user(
            data=RegisterUserInput.model_validate(data),
        )
        resp.media = result.model_dump(mode="json")
        resp.status = HTTP_201
        

How to fix this error? Im stuck as the documentation doesn't seem that clear!

@ivankorobkov
Copy link
Owner

Hi aryaniyaps,

Thank you for reporting a bug and providing all the info.

@fzyukio excuse me, could you check what's the problem here? Maybe you see the solution?

@ivankorobkov
Copy link
Owner

@aryaniyaps I'm sorry. I'll take a look in a couple of days. A little busy just now.

@aryaniyaps
Copy link
Author

@ivankorobkov sure, take your time! It would be really useful to be able to use async contextmanagers fully though..

@jeanlst
Copy link

jeanlst commented Jan 24, 2024

Any news on this @ivankorobkov ?

@ivankorobkov
Copy link
Owner

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

No branches or pull requests

3 participants