I run
$ python run.py db init
And that runs without issue. Then,
$ python run.py db migrate -m 'First migration'
Traceback (most recent call last):
File "run.py", line 3, in <module>
myapp.manager.run()
File "/Users/bfh/.virtualenvs/myapp/lib/python2.7/site-packages/flask_script/__init__.py", line 412, in run
result = self.handle(sys.argv[0], sys.argv[1:])
File "/Users/bfh/.virtualenvs/myapp/lib/python2.7/site-packages/flask_script/__init__.py", line 383, in handle
res = handle(*args, **config)
File "/Users/bfh/.virtualenvs/myapp/lib/python2.7/site-packages/flask_script/commands.py", line 216, in __call__
return self.run(*args, **kwargs)
File "/Users/bfh/.virtualenvs/myapp/lib/python2.7/site-packages/flask_migrate/__init__.py", line 136, in migrate
version_path=version_path, rev_id=rev_id)
File "/Users/bfh/.virtualenvs/myapp/lib/python2.7/site-packages/alembic/command.py", line 113, in revision
script.run_env()
File "/Users/bfh/.virtualenvs/myapp/lib/python2.7/site-packages/alembic/script.py", line 390, in run_env
util.load_python_file(self.dir, 'env.py')
File "/Users/bfh/.virtualenvs/myapp/lib/python2.7/site-packages/alembic/util.py", line 243, in load_python_file
module = load_module_py(module_id, path)
File "/Users/bfh/.virtualenvs/myapp/lib/python2.7/site-packages/alembic/compat.py", line 79, in load_module_py
mod = imp.load_source(module_id, path, fp)
File "migrations/env.py", line 19, in <module>
config.set_main_option('sqlalchemy.url', current_app.config.get('SQLALCHEMY_DATABASE_URI'))
File "/Users/bfh/.virtualenvs/myapp/lib/python2.7/site-packages/alembic/config.py", line 198, in set_main_option
self.file_config.set(self.config_ini_section, name, value)
File "/System/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/ConfigParser.py", line 743, in set
raise TypeError("option values must be strings")
TypeError: <flask_script.commands.Command object at 0x107aba950>: option values must be strings
Any advice for a fella?
Do you have SQLALCHEMY_DATABASE_URI set in your project's configuration?
Oh geez, Miguel, my apologies. I made a bunch of configuration changes. This is a direct result of that refactoring. Thanks very much for the quick reply.
@miguelgrinberg Thanks that reply saved me big time
Running into this old problem, but in my case my Config file looks correct. Here's the trace:
flask db migrate -m "test"
Traceback (most recent call last):
File "/home/haroon/PycharmProjects/federations/venv/bin/flask", line 11, in <module>
sys.exit(main())
File "/home/haroon/PycharmProjects/federations/venv/lib/python3.5/site-packages/flask/cli.py", line 894, in main
cli.main(args=args, prog_name=name)
File "/home/haroon/PycharmProjects/federations/venv/lib/python3.5/site-packages/flask/cli.py", line 557, in main
return super(FlaskGroup, self).main(*args, **kwargs)
File "/home/haroon/PycharmProjects/federations/venv/lib/python3.5/site-packages/click/core.py", line 697, in main
rv = self.invoke(ctx)
File "/home/haroon/PycharmProjects/federations/venv/lib/python3.5/site-packages/click/core.py", line 1066, in invoke
return _process_result(sub_ctx.command.invoke(sub_ctx))
File "/home/haroon/PycharmProjects/federations/venv/lib/python3.5/site-packages/click/core.py", line 1066, in invoke
return _process_result(sub_ctx.command.invoke(sub_ctx))
File "/home/haroon/PycharmProjects/federations/venv/lib/python3.5/site-packages/click/core.py", line 895, in invoke
return ctx.invoke(self.callback, **ctx.params)
File "/home/haroon/PycharmProjects/federations/venv/lib/python3.5/site-packages/click/core.py", line 535, in invoke
return callback(*args, **kwargs)
File "/home/haroon/PycharmProjects/federations/venv/lib/python3.5/site-packages/click/decorators.py", line 17, in new_func
return f(get_current_context(), *args, **kwargs)
File "/home/haroon/PycharmProjects/federations/venv/lib/python3.5/site-packages/flask/cli.py", line 412, in decorator
return __ctx.invoke(f, *args, **kwargs)
File "/home/haroon/PycharmProjects/federations/venv/lib/python3.5/site-packages/click/core.py", line 535, in invoke
return callback(*args, **kwargs)
File "/home/haroon/PycharmProjects/federations/venv/lib/python3.5/site-packages/flask_migrate/cli.py", line 90, in migrate
rev_id, x_arg)
File "/home/haroon/PycharmProjects/federations/venv/lib/python3.5/site-packages/flask_migrate/__init__.py", line 197, in migrate
version_path=version_path, rev_id=rev_id)
File "/home/haroon/PycharmProjects/federations/venv/lib/python3.5/site-packages/alembic/command.py", line 176, in revision
script_directory.run_env()
File "/home/haroon/PycharmProjects/federations/venv/lib/python3.5/site-packages/alembic/script/base.py", line 427, in run_env
util.load_python_file(self.dir, 'env.py')
File "/home/haroon/PycharmProjects/federations/venv/lib/python3.5/site-packages/alembic/util/pyfiles.py", line 81, in load_python_file
module = load_module_py(module_id, path)
File "/home/haroon/PycharmProjects/federations/venv/lib/python3.5/site-packages/alembic/util/compat.py", line 83, in load_module_py
spec.loader.exec_module(module)
File "<frozen importlib._bootstrap_external>", line 665, in exec_module
File "<frozen importlib._bootstrap>", line 222, in _call_with_frames_removed
File "migrations/env.py", line 22, in <module>
current_app.config.get)
File "/home/haroon/PycharmProjects/federations/venv/lib/python3.5/site-packages/alembic/config.py", line 218, in set_main_option
self.set_section_option(self.config_ini_section, name, value)
File "/home/haroon/PycharmProjects/federations/venv/lib/python3.5/site-packages/alembic/config.py", line 245, in set_section_option
self.file_config.set(section, name, value)
File "/usr/lib/python3.5/configparser.py", line 1189, in set
self._validate_value_types(option=option, value=value)
File "/usr/lib/python3.5/configparser.py", line 1174, in _validate_value_types
raise TypeError("option values must be strings")
TypeError: option values must be strings
any help would be much appreciated
my config file:
import os
basedir = os.path.abspath(os.path.dirname(__file__))
class Config(object):
SECRET_KEY = os.environ.get('SECRET_KEY') or "you'll never guess"
SQLALCHEMY_DATABASE_URI = os.environ.get('DATABASE_URL') or 'sqlite:///' + os.path.join(basedir, 'app.db')
SQLALCHEMY_TRACK_MODIFICATIONS = False
UPLOADED_PHOTOS_DEST = 'app/static/photos/'
UPLOADED_PHOTOS_URL = 'static/photos/'
Are you sure you are importing the configuration into your Flask application instance?
pretty sure..here is my __init__.py file...I am trying the factory pattern that you go over in your blog. Thanks much for the help.
from flask import Flask, g
from flask_sqlalchemy import SQLAlchemy
from flask_migrate import Migrate
from flask_login import LoginManager
from config import Config
from flask_restful import Api
from flask_httpauth import HTTPBasicAuth
from flask_uploads import UploadSet, configure_uploads, IMAGES
api = Api()
migrate = Migrate()
login = LoginManager()
db = SQLAlchemy()
auth = HTTPBasicAuth()
from .resources.token import Token
from .resources.therapists import Availability, AccountInfo, Profile, Register, Therapists, SingleTherapist
api.add_resource(Token, '/token')
api.add_resource(Availability, '/therapist/availability')
api.add_resource(AccountInfo, '/therapist/account')
api.add_resource(Profile, '/therapist/profile')
api.add_resource(Therapists, '/therapists')
api.add_resource(SingleTherapist, '/therapist')
api.add_resource(Register, '/therapist/register')
def create_app(config_class=Config):
app = Flask(__name__)
app.config.from_object(config_class)
db.init_app(app)
migrate.init_app(app, db)
login.init_app(app)
api.init_app(app)
photos = UploadSet('photos', IMAGES)
configure_uploads(app=app, upload_sets=photos)
return app
from app import models
@auth.verify_password
def verify_password(username_or_token, password):
therapist = models.Therapist.verify_token(username_or_token)
if not therapist:
therapist = models.Therapist.query.filter_by(username=username_or_token).first()
if not therapist or not therapist.check_password(password):
return False
g.therapist = therapist
return True
in case this helps, here are my models:
from flask import current_app
from flask_validator import ValidateEmail, ValidateError
from flask_login import UserMixin
from app import db
from werkzeug.security import check_password_hash, generate_password_hash
from itsdangerous import (TimedJSONWebSignatureSerializer as Serializer, BadSignature, SignatureExpired)
import re
from datetime import datetime
from dateutil import parser
class Member(UserMixin, db.Model):
"""
username, email, password
"""
__tablename__ = 'member'
__table_args__ = {'extend_existing': True}
id = db.Column(db.Integer, primary_key=True)
username = db.Column(db.String(60), unique=True, nullable=False)
email = db.Column(db.String(60), unique=True, nullable=False)
passwordHash = db.Column(db.String(120))
type = db.Column(db.String(10))
__mapper_args__ = {
'polymorphic_on': type,
'polymorphic_identity': 'member'
}
def set_password(self, password):
if self.valid(password):
self.passwordHash = generate_password_hash(password)
else:
raise ValidateError('Password Invalid')
def check_password(self, password):
return check_password_hash(self.passwordHash, password)
@staticmethod
def valid(password):
"""
checks if a string is a valid email format
:param password: the candidate string
:return: True if conditions met, else false
"""
lowers = bool(re.search('[a-z]', password))
uppers = bool(re.search('[A-Z]', password))
numbers = bool(re.search(r'\d', password))
long_enough = len(password) >= 8
return lowers and uppers and numbers and long_enough
@classmethod
def __declare_last__(self):
ValidateEmail(Member.email, throw_exception=True, message='Invalid Email')
def generate_token(self, expiration=3600):
s = Serializer(current_app.config['SECRET_KEY'], expires_in=expiration)
return s.dumps(self.id)
@staticmethod
def verify_token(token):
s = Serializer(current_app.config['SECRET_KEY'])
try:
therapist_id = s.loads(token)
except BadSignature:
return None
except SignatureExpired:
return None
therapist = Therapist.query.get(therapist_id)
return therapist
class Therapist(Member):
__mapper_args__ = {
'polymorphic_identity': 'therapist'
}
class Customer(Member):
__mapper_args__ = {
'polymorphic_identity': 'customer'
}
class Event(db.Model):
"""
member, time, type, location
"""
id = db.Column(db.Integer, primary_key=True)
member = db.Column(db.Integer, db.ForeignKey('member.id'))
time = db.Column(db.DateTime)
type = db.Column(db.String(60), nullable=False)
location = db.Column(db.String(60))
@staticmethod
def set_time(raw):
try:
dt = parser.parse(raw)
if dt > datetime.now():
return parser.parse(raw)
else:
raise ValidateError('You can only book future events')
except Exception:
raise ValidateError('Cannot recognize date format')
# TODO: Tests
class Appointment(db.Model):
"""
event, customer, description
"""
id = db.Column(db.Integer, primary_key=True)
event = db.Column(db.Integer, db.ForeignKey('event.id'))
customer = db.Column(db.Integer, db.ForeignKey('member.id'))
description = db.Column(db.String(140))
# TODO: Tests
class Account(db.Model):
"""
therapist, account_number, sort_code
"""
id = db.Column(db.Integer, primary_key=True)
therapist = db.Column(db.Integer, db.ForeignKey('member.id'), unique=True)
account_number = db.Column(db.Integer, nullable=False)
sort_code = db.Column(db.Integer, nullable=False)
# TODO: Tests
class Profile(db.Model):
"""
therapist, firstname, lastname, photo, description
"""
id = db.Column(db.Integer, primary_key=True)
therapist = db.Column(db.Integer, db.ForeignKey('member.id'), unique=True)
firstName = db.Column(db.String(60), nullable=False)
lastName = db.Column(db.String(60), nullable=False)
photo = db.Column(db.String(60))
description = db.Column(db.String(140))
# TODO:Tests
class Therapy(db.Model):
"""
profile, therapy
"""
id = db.Column(db.Integer, primary_key=True)
profile = db.Column(db.Integer, db.ForeignKey('profile.id'))
therapy = db.Column(db.String(60), nullable=False)
# TODO:Tests
class Transaction(db.Model):
"""
appointment, tokens, tokenValue, totalCash, cashShare
"""
DEFAULT_TOKEN_VALUE = 1.0
DEFAULT_CASHSHARE = 0.2
id = db.Column(db.Integer, primary_key=True)
appointment = db.Column(db.Integer, db.ForeignKey('appointment.id'))
tokens = db.Column(db.Integer, nullable=False)
tokenValue = db.Column(db.Float, default=DEFAULT_TOKEN_VALUE, nullable=False)
totalCash = db.Column(db.Float, nullable=False)
cashShare = db.Column(db.Float, default=DEFAULT_CASHSHARE, nullable=False)
@haroonhassan well, the stack trace does not lie, if I'm not mistaken line 22 in migrations/env.py is the line where Alembic tries to get the database URL. You may want to add a print statement above that line to confirm that the configuration is actually available in current_app.config.
@miguelgrinberg Not sure how, but the arguments to config.get() somehow got deleted. So after line 22 the function object was being passed. Thanks very much for the guidance.
I am also getting this error. I am connecting to mysql in config, quite sure it is pasted correctly. Any advice what could be the issue?
Response for _flask db migrate -m "users table"_
> Traceback (most recent call last):
> File "/usr/local/bin/flask", line 11, in <module>
> sys.exit(main())
> File "/usr/local/lib/python3.5/dist-packages/flask/cli.py", line 894, in main
> cli.main(args=args, prog_name=name)
> File "/usr/local/lib/python3.5/dist-packages/flask/cli.py", line 557, in main
> return super(FlaskGroup, self).main(*args, **kwargs)
> File "/usr/local/lib/python3.5/dist-packages/click/core.py", line 697, in main
> rv = self.invoke(ctx)
> File "/usr/local/lib/python3.5/dist-packages/click/core.py", line 1066, in invoke
> return _process_result(sub_ctx.command.invoke(sub_ctx))
> File "/usr/local/lib/python3.5/dist-packages/click/core.py", line 1066, in invoke
> return _process_result(sub_ctx.command.invoke(sub_ctx))
> File "/usr/local/lib/python3.5/dist-packages/click/core.py", line 895, in invoke
> return ctx.invoke(self.callback, **ctx.params)
> File "/usr/local/lib/python3.5/dist-packages/click/core.py", line 535, in invoke
> return callback(*args, **kwargs)
> File "/usr/local/lib/python3.5/dist-packages/click/decorators.py", line 17, in new_func
> return f(get_current_context(), *args, **kwargs)
> File "/usr/local/lib/python3.5/dist-packages/flask/cli.py", line 412, in decorator
> return __ctx.invoke(f, *args, **kwargs)
> File "/usr/local/lib/python3.5/dist-packages/click/core.py", line 535, in invoke
> return callback(*args, **kwargs)
> File "/usr/local/lib/python3.5/dist-packages/flask_migrate/cli.py", line 90, in migrate
> rev_id, x_arg)
> File "/usr/local/lib/python3.5/dist-packages/flask_migrate/__init__.py", line 95, in wrapped
> f(*args, **kwargs)
> File "/usr/local/lib/python3.5/dist-packages/flask_migrate/__init__.py", line 215, in migrate
> version_path=version_path, rev_id=rev_id)
> File "/usr/local/lib/python3.5/dist-packages/alembic/command.py", line 176, in revision
> script_directory.run_env()
> File "/usr/local/lib/python3.5/dist-packages/alembic/script/base.py", line 427, in run_env
> util.load_python_file(self.dir, 'env.py')
> File "/usr/local/lib/python3.5/dist-packages/alembic/util/pyfiles.py", line 81, in load_python_file
> module = load_module_py(module_id, path)
> File "/usr/local/lib/python3.5/dist-packages/alembic/util/compat.py", line 82, in load_module_py
> spec.loader.exec_module(module)
> File "<frozen importlib._bootstrap_external>", line 665, in exec_module
> File "<frozen importlib._bootstrap>", line 222, in _call_with_frames_removed
> File "migrations/env.py", line 22, in <module>
> current_app.config.get('SQLALCHEMY_DATABASE_URI'))
> File "/usr/local/lib/python3.5/dist-packages/alembic/config.py", line 218, in set_main_option
> self.set_section_option(self.config_ini_section, name, value)
> File "/usr/local/lib/python3.5/dist-packages/alembic/config.py", line 245, in set_section_option
> self.file_config.set(section, name, value)
> File "/usr/lib/python3.5/configparser.py", line 1189, in set
> self._validate_value_types(option=option, value=value)
> File "/usr/lib/python3.5/configparser.py", line 1174, in _validate_value_types
> raise TypeError("option values must be strings")
> TypeError: option values must be strings
config.py is defined as:
import os
class Config(object):
SECRET_KEY = os.environ.get('SECRET_KEY') or 'you-will-never-guess'
class Config(object):
SQLALCHEMY_DATABASE_URI = os.environ.get('mysql://root:mypassword@localhost/mydatabase')
SQLALCHEMY_TRACK_MODIFICATIONS = False
@sim0nsl Do this instead:
class Config(object):
SECRET_KEY = os.environ.get('SECRET_KEY') or 'you-will-never-guess'
SQLALCHEMY_DATABASE_URI = os.environ.get('DATABASE_URL')
SQLALCHEMY_TRACK_MODIFICATIONS = False
And then set the following in your environment before running the flask db migrate command:
export DATABASE_URL=mysql://root:mypassword@localhost/mydatabase
@miguelgrinberg That is neat! I confirm it is working. Thank you.
@haroonhassan well, the stack trace does not lie, if I'm not mistaken line 22 in migrations/env.py is the line where Alembic tries to get the database URL. You may want to add a print statement above that line to confirm that the configuration is actually available in
current_app.config.
Thank you @miguelgrinberg! I was having a similar issue and resolved it by troubleshooted using the migrations/env.py file.
Most helpful comment
Do you have
SQLALCHEMY_DATABASE_URIset in your project's configuration?