flask-pw
flask-pw copied to clipboard
Does Not Play Nicely with Application Factories.
So, I am trying to use this library, mostly so I can use the wonderful peewee_migrate
and get auto-migrations. However, this library does not play well with Flask Application factories. Whenever I try to simply import my models before my app is created, I get this error:
===================================================== ERRORS =====================================================
___________________________________ ERROR collecting tests/test_user_model.py ____________________________________
tests/test_user_model.py:5: in <module>
from transfers.models.user import User
transfers/models/user.py:10: in <module>
from transfers.models.base import BaseModel
transfers/models/base.py:12: in <module>
class BaseModel(db.Model):
.pyenv/lib/python3.6/site-packages/cached_property.py:26: in __get__
value = obj.__dict__[self.func.__name__] = self.func(obj)
.pyenv/lib/python3.6/site-packages/flask_pw/__init__.py:78: in Model
Model_ = self.app.config['PEEWEE_MODELS_CLASS']
E AttributeError: 'NoneType' object has no attribute 'config'
Because the library is trying to access the config before the app is created.
Here is my general app structure:
# transfers/app.py
from flask import Flask
from transfers.models import db
def create_app(settings=None):
app = Flask('transfers')
db.init_app(app)
app.db = db
return app
# transfers/models/__init__.py
from flask_pw import Peewee
db = Peewee()
def load_models():
# has to be inner so we don't hit this error
from .transfer import Transfer # pylint: disable=wrong-import-position, unused-variable
from .user import User # pylint: disable=wrong-import-position, unused-variable
# transfers/models/user.py
import peewee
from transfers.models import db
class User(db.Model):
email = peewee.CharField(max_length=255)
first_name = peewee.CharField(max_length=128, db_column='firstName')
last_name = peewee.CharField(max_length=128, db_column='lastName')
points = peewee.DecimalField(max_digits=6, decimal_places=2, default=0)
Then, simply writing this test will produce the above error:
# tests/test_user_model.py
"""Tests for the user model."""
from transfers.models.user import User
This happens because there is no application properly initialized when pytest loads the file, so everything breaks. The only fix for this is doing an inner import on your models in every single test to make sure the app and proxy are properly created. This creates a bad developer experience.
In the above examples, I have omitted some code, but none of it is very important. For example, the BaseModel
simply extends db.Model
and adds some timestamp related fields.