05bit / peewee-async

Asynchronous interface for peewee ORM powered by asyncio
http://peewee-async-lib.readthedocs.io
MIT License
733 stars 100 forks source link

Some queries always result in a stack overflow #74

Open skewty opened 7 years ago

skewty commented 7 years ago

Some queries always result in a stack overflow. The below code works using playhouse.postgres_ext.PostgresqlExtDatabase but doesn't if I switch to peewee_async.PostgresqlDatabase.

from peewee import Model, ForeignKeyField, CharField, BooleanField, DoubleField, IntegerField, \
    SmallIntegerField, CompositeKey, PrimaryKeyField, FloatField
from peewee_async import Manager, PostgresqlDatabase
from playhouse.postgres_ext import JSONField, PostgresqlExtDatabase

# database = PostgresqlDatabase(
#     database=DATABASE['name'],
#     host=DATABASE['host'],
#     port=DATABASE['port'],
#     user=DATABASE['user'],
#     password=DATABASE['password'],
#     # register_hstore=False,
# )
# database.set_allow_sync(True)

database = PostgresqlExtDatabase(
    database=DATABASE['name'],
    host=DATABASE['host'],
    port=DATABASE['port'],
    user=DATABASE['user'],
    password=DATABASE['password'],
    register_hstore=False,
)

class AsyncBaseModel(Model):
    class Meta:
        database = database

class AlarmHistory(AsyncBaseModel):
    id = PrimaryKeyField()
    alarm_type = CharField(max_length=MAX_ID_LABEL_LENGTH, null=False)
    activation = ForeignKeyField(FeatureHistory, null=False, related_name='activations')
    normalization = ForeignKeyField(FeatureHistory, default=None, null=True,  
                                    related_name='normalizations')
    ack_username = CharField(max_length=MAX_USERNAME_LENGTH, null=True)
    ack_notes = CharField(default=None, null=True)
    ack_timestamp = TimestampField(null=True)

class FeatureHistory(AsyncBaseModel):
    id = PrimaryKeyField()
    timestamp = TimestampField(null=False, default=time)
    identifier = CharField(max_length=MAX_IDENTIFIER_LENGTH, null=False)
    message_format_short = CharField(null=True)
    message_format_long = CharField(null=True)
    user_data = JSONField(null=True)
    system_data = JSONField(null=True)
    filter = CharField(max_length=MAX_ID_LABEL_LENGTH, null=False)
    icon_state = CharField(max_length=MAX_ID_LABEL_LENGTH, null=False)
    tile_set = CharField(max_length=MAX_ID_LABEL_LENGTH, null=True)
    longitude = DoubleField(null=True)
    lattitude = DoubleField(null=True)
    zone_name = CharField(max_length=MAX_ZONE_NAME_LENGTH, null=True)
    battery_percentage = IntegerField(default=None, null=True)

This method will cause a stack overflow if I use peewee_async.PostgresqlDatabase:

def get_alarm_history(from_ts: float, to_ts: float) -> Iterable[dict]:
    q = AlarmHistory.select(
        AlarmHistory.activation,
        AlarmHistory.ack_username,
        AlarmHistory.ack_notes,
        AlarmHistory.ack_timestamp,
        FeatureHistory.identifier,
        FeatureHistory.timestamp,
        FeatureHistory.user_data['owner'].alias('owner'),
        FeatureHistory.user_data['tag#'].alias('tag'),
        FeatureHistory.system_data['zone_name'].alias('zone_name'),
    ).join(
        FeatureHistory, on=(AlarmHistory.activation == FeatureHistory.id)
    ).where(
        FeatureHistory.icon_state == IconState.values.REGULAR_ACTIVE,
        AlarmHistory.alarm_type == AlarmType.values.FEATURE_STATE_ALARM,
        FeatureHistory.timestamp >= from_ts,
        FeatureHistory.timestamp <= to_ts,
    ).order_by(FeatureHistory.timestamp)
    q = tuple(q.dicts())
    return q
rudyryk commented 6 years ago

@skewty Thanks for reporting. Just probably this is because you're using peewee_async.PostgresqlDatabase but not peewee_asyncext. PostgresqlExtDatabase, which is closer replacement for sync extended version.