nickjj / build-a-saas-app-with-flask

Learn how to build a production ready web app with Flask and Docker.
https://buildasaasappwithflask.com
MIT License
954 stars 185 forks source link

Error importing module add: #30

Closed vblackburn closed 8 years ago

vblackburn commented 8 years ago

I've been playing around with the code and tried to remove the billing and streaming, this meant I also remove the click commands for the billing and streaming features. Though now when I try to run it I am getting this error,

Error importing module add:
add

Do you know what may be causing click to not be able to import the commands and do you have any ideas about how I might fix this bug. Thanks

nickjj commented 8 years ago

Hi,

My best guess is you removed all of the billing components but the add command is still referencing billing modules so it explodes: https://github.com/nickjj/build-a-saas-app-with-flask/blob/master/cli/commands/cmd_add.py

That error stems from this: https://github.com/nickjj/build-a-saas-app-with-flask/blob/master/cli/cli.py#L42

The likely fix would be to go over the cmd_add.py file's contents and remove all traces of the billing/streaming components. If you get the same type of error in other commands, then repeat the process for those.

vblackburn commented 8 years ago

I checked and I have removed the billing and stream commands from the add all component at the end.

On 15 Dec 2015, at 15:59, Nick Janetakis notifications@github.com wrote:

Hi,

My best guess is you removed all of the billing components but the add command is still referencing billing modules so it explodes: https://github.com/nickjj/build-a-saas-app-with-flask/blob/master/cli/commands/cmd_add.py

That error stems from this: https://github.com/nickjj/build-a-saas-app-with-flask/blob/master/cli/cli.py#L42

— Reply to this email directly or view it on GitHub.

nickjj commented 8 years ago

Can you gist or paste in your entire cmd_add.py file if it's still throwing that error.

vblackburn commented 8 years ago
import logging
import random
from datetime import datetime

import click
from faker import Faker

SEED_ADMIN_EMAIL = None
ACCEPT_LANGUAGES = None

try:
    from instance import settings

    SEED_ADMIN_EMAIL = settings.SEED_ADMIN_EMAIL
    ACCEPT_LANGUAGES = settings.ACCEPT_LANGUAGES
except ImportError:
    logging.error('Ensure __init__.py and settings.py both exist in instance/')
    exit(1)
except AttributeError:
    from config import settings

    if SEED_ADMIN_EMAIL is None:
        SEED_ADMIN_EMAIL = settings.SEED_ADMIN_EMAIL

    if ACCEPT_LANGUAGES is None:
        ACCEPT_LANGUAGES = settings.ACCEPT_LANGUAGES

from scrumbox.app import create_app
from scrumbox.extensions import db
from scrumbox.blueprints.issue.models import Issue
from scrumbox.blueprints.user.models import User

fake = Faker()
app = create_app()
db.app = app

def _log_status(count, model_label):
    """
    Log the output of how many records were created.

    :param count: Amount created
    :type count: int
    :param model_label: Name of the model
    :type model_label: str
    :return: None
    """
    click.echo('Created {0} {1}'.format(count, model_label))

    return None

def _bulk_insert(model, data, label):
    """
    Bulk insert data to a specific model and log it.

    :param model: Model being affected
    :type model: SQLAlchemy
    :param data: Data to be saved
    :type data: list
    :param label: Label for the output
    :type label: str
    :return: None
    """
    with app.app_context():
        model.query.delete()
        db.session.commit()
        db.engine.execute(model.__table__.insert(), data)

        _log_status(model.query.count(), label)

    return None

@click.group()
def cli():
    """ Populate your db with generated data. """
    pass

@click.command()
def users():
    """
    Create random users.
    """
    random_emails = []
    data = []

    # Ensure we get about 50 unique random emails, +1 due to the seeded email.
    for i in range(0, 49):
        random_emails.append(fake.email())

    random_emails.append(SEED_ADMIN_EMAIL)
    random_emails = list(set(random_emails))

    while True:
        if len(random_emails) == 0:
            break

        email = random_emails.pop()

        params = {
            'role': random.choice(User.ROLE.keys()),
            'email': email,
            'password': User.encrypt_password('password'),
            'name': fake.name(),
            'locale': random.choice(ACCEPT_LANGUAGES)
        }

        # Ensure the seeded admin is always an admin.
        if email == SEED_ADMIN_EMAIL:
            params['role'] = 'admin'
            params['locale'] = 'en'

        data.append(params)

    return _bulk_insert(User, data, 'users')

@click.command()
def issues():
    """
    Create random issues.
    """
    data = []

    for i in range(0, 50):
        params = {
            'status': random.choice(Issue.STATUS.keys()),
            'label': random.choice(Issue.LABEL.keys()),
            'email': fake.email(),
            'question': fake.paragraph()
        }

        data.append(params)

    return _bulk_insert(Issue, data, 'issues')

@click.command()
@click.pass_context
def all(ctx):
    """
    Populate everything at once.

    :param ctx:
    :return: None
    """
    ctx.invoke(users)
    ctx.invoke(issues)

    return None

cli.add_command(users)
cli.add_command(issues)
cli.add_command(all)
nickjj commented 8 years ago

Hmm, can you rename this file from cmd_add.py to foo.py and see if everything works. This will help isolate whether or not this file is causing the issue.

I don't see any billing/streaming related info in that file.

vblackburn commented 8 years ago

This is the error I get after renaming it, it doesn't seem to be an issue with the add file itself but rather trying to import any of the commands. I tried just typing run and that was the error thrown back

Error importing module db:
db
nickjj commented 8 years ago

There's very likely a reference to something related to billing/streaming somewhere else in the code base.

You can try removing the try/catch block in: https://github.com/nickjj/build-a-saas-app-with-flask/blob/master/cli/cli.py#L29

Hopefully it spits out a more useful error.

vblackburn commented 8 years ago

I've gotten an error saying;

    from scrumbox.blueprints.admin.forms import SearchForm, BulkDeleteForm, \
ImportError: cannot import name UserCancelSubscriptionForm

Though within the file itself I have already removed the UserCancelSubscriptionForm;

import logging
from collections import OrderedDict

from flask_wtf import Form
from wtforms import SelectField, StringField, BooleanField, TextAreaField, \
    FloatField, DateTimeField
from wtforms.validators import DataRequired, Length, Optional, Regexp, \
    NumberRange
from wtforms_components import Unique, EmailField, IntegerField
from flask_babel import lazy_gettext as _

try:
    from instance import settings

    LANGUAGES = settings.LANGUAGES
except ImportError:
    logging.error('Ensure __init__.py and settings.py both exist in instance/')
    exit(1)
except AttributeError:
    from config import settings

    LANGUAGES = settings.LANGUAGES

from scrumbox.lib.locale import Currency
from scrumbox.lib.util_wtforms import ModelForm, choices_from_dict
from scrumbox.blueprints.user.models import db, User
from scrumbox.blueprints.issue.models import Issue

class SearchForm(Form):
    q = StringField(_('Search terms'), [Optional(), Length(1, 128)])

class BulkDeleteForm(Form):
    SCOPE = OrderedDict([
        ('all_selected_products', 'All selected items'),
        ('all_search_results', 'All search results')
    ])

    scope = SelectField(_('Privileges'), [DataRequired()],
                        choices=choices_from_dict(SCOPE, prepend_blank=False))

class UserForm(ModelForm):
    username_message = _('Letters, numbers and underscores only please.')

    username = StringField(validators=[
        Unique(
            User.username,
            get_session=lambda: db.session
        ),
        Optional(),
        Length(1, 16),
        Regexp('^\w+$', message=username_message)
    ])
    name = StringField(_('Full name'), [Optional(), Length(1, 128)])
    role = SelectField(_('Privileges'), [DataRequired()],
                       choices=choices_from_dict(User.ROLE,
                                                 prepend_blank=False))
    active = BooleanField(_('Yes, allow this user to sign in'))
    locale = SelectField(_('Language preference'), [DataRequired()],
                         choices=choices_from_dict(LANGUAGES))

class IssueForm(Form):
    label = SelectField(_('What do you need help with?'), [DataRequired()],
                        choices=choices_from_dict(Issue.LABEL))
    email = EmailField(_("What's your e-mail address?"),
                       [DataRequired(), Length(3, 254)])
    question = TextAreaField(_("What's your question or issue?"),
                             [DataRequired(), Length(1, 8192)])
    status = SelectField(_('What status is the issue in?'), [DataRequired()],
                         choices=choices_from_dict(Issue.STATUS,
                                                   prepend_blank=False))

class IssueContactForm(Form):
    subject = StringField(_('Subject'), [DataRequired(), Length(1, 254)])
    message = TextAreaField(_('Message to be sent'),
                            [DataRequired(), Length(1, 8192)])

I know i still have a few redundant imports such as the Currency import but the currency library is still in the lib folder so it should cause an issue.

vblackburn commented 8 years ago

Ok i found an instance of trying to import UserCancelSubscriptionForm in admin.views, and removed it im now getting and error saying;

RuntimeError: Flask-Webpack requires 'WEBPACK_MANIFEST_PATH' to be set and it must point to a valid json file.

which I'm guessing is another environmental variable i need to set

vblackburn commented 8 years ago

Ok so building on the above error in the config file webpack path looks like this;

# Flask-Webpack (assets) settings.
WEBPACK_MANIFEST_PATH = path.join(APP_ROOT, 'build', 'manifest.json')

I haven't changed it from the original, is there a reason that it is now invalid? Thanks

nickjj commented 8 years ago

You just need to build the assets once to create the initial manifest.json file. Then you'll never have to worry about that again. The environment variable can stay as is.

You can do that by running: run assets build

vblackburn commented 8 years ago

It's works! Thank you