peewee-async icon indicating copy to clipboard operation
peewee-async copied to clipboard

no way to pass async driver only kwargs if i need to run sync code

Open trim21 opened this issue 6 years ago • 1 comments

I want to use aiomysql's pool_recycle feature, so I create my db pool like this

db = peewee_async.PooledMySQLDatabase(
    config.MYSQL_DB,
    host=config.MYSQL_HOST,
    user=config.MYSQL_USER,
    password=config.MYSQL_PASSWORD,
    charset='utf8mb4',
    pool_recycle=3600
)

It works fine if i only do async query.

But the problem is that I need to create some tables in my test code so I do this

    with objects.allow_sync():
        Table1.create_table()
        Table2.create_table()

And i got

INTERNALERROR>   File "c:\users\trim21\.virtualenvs\personal-website\lib\site-packages\peewee.py", line 6292, in create_table
INTERNALERROR>     and cls.table_exists():
INTERNALERROR>   File "c:\users\trim21\.virtualenvs\personal-website\lib\site-packages\peewee.py", line 6282, in table_exists
INTERNALERROR>     return cls._schema.database.table_exists(M.table.__name__, M.schema)
INTERNALERROR>   File "c:\users\trim21\.virtualenvs\personal-website\lib\site-packages\peewee.py", line 3110, in table_exists
INTERNALERROR>     return table_name in self.get_tables(schema=schema)
INTERNALERROR>   File "c:\users\trim21\.virtualenvs\personal-website\lib\site-packages\peewee.py", line 3770, in get_tables
INTERNALERROR>     return [table for table, in self.execute_sql(query, ('VIEW',))]
INTERNALERROR>   File "c:\users\trim21\.virtualenvs\personal-website\lib\site-packages\peewee_async.py", line 977, in execute_sql
INTERNALERROR>     return super().execute_sql(*args, **kwargs)
INTERNALERROR>   File "c:\users\trim21\.virtualenvs\personal-website\lib\site-packages\peewee.py", line 2947, in execute_sql
INTERNALERROR>     cursor = self.cursor(commit)
INTERNALERROR>   File "c:\users\trim21\.virtualenvs\personal-website\lib\site-packages\peewee.py", line 2933, in cursor
INTERNALERROR>     self.connect()
INTERNALERROR>   File "c:\users\trim21\.virtualenvs\personal-website\lib\site-packages\peewee.py", line 2891, in connect
INTERNALERROR>     self._state.set_connection(self._connect())
INTERNALERROR>   File "c:\users\trim21\.virtualenvs\personal-website\lib\site-packages\peewee.py", line 3741, in _connect
INTERNALERROR>     conn = mysql.connect(db=self.database, **self.connect_params)
INTERNALERROR>   File "c:\users\trim21\.virtualenvs\personal-website\lib\site-packages\pymysql\__init__.py", line 94, in Connect
INTERNALERROR>     return Connection(*args, **kwargs)
INTERNALERROR> TypeError: __init__() got an unexpected keyword argument 'pool_recycle'

This is because peewee will try to create a pymysql connection , and try to pass pool_recycle to pymysql connection. But it should only be used in async connection.

After I read the source i found that there is no way to pass async only option to peewee_async.PooledMySQLDatabase, peewee_async.PooledMySQLDatabase.connect_params_async is a property without setter, and connect_params will be passed to pymysql Connection, too.

trim21 avatar Jun 20 '19 20:06 trim21

As a workaround

import peewee_async

from app.core import config


class AsyncMySQLConnection(peewee_async.AsyncMySQLConnection):
    """Asynchronous database connection pool.
    """

    def __init__(self, *, database=None, loop=None, timeout=None, **kwargs):
        self.pool = None
        self.loop = loop
        self.database = database
        self.timeout = timeout
        kwargs.setdefault('pool_recycle', 3600)
        self.connect_params = kwargs


db = peewee_async.PooledMySQLDatabase(
    config.MYSQL_DB,
    host=config.MYSQL_HOST,
    user=config.MYSQL_USER,
    password=config.MYSQL_PASSWORD,
    charset='utf8mb4',
    async_conn=AsyncMySQLConnection,
)

trim21 avatar Jun 20 '19 20:06 trim21

Another approach would be to subclass peewee_async.PooledMySQLDatabase and override the connect_params_async property.

    @property
    def connect_params_async(self):
        """Connection parameters for `aiomysql.Connection`
        """
        kwargs = self.connect_params.copy()
        kwargs.update({
            'minsize': self.min_connections,
            'maxsize': self.max_connections,
            'autocommit': True,
            'pool_recycle': 3600,
        })
        return kwargs

I'm not sure what proper solution would be here. Having a single constructor interface for actually two different classes is not great in the first place and could lead to such incompatibilities. But also we don't want to deviate much from original peewee's interface.

I suggest to stick to explicitly overriding the connect_params_async until we find something better.

rudyryk avatar May 04 '24 17:05 rudyryk