Why won't my flask command work on Heroku? - heroku

I have a simple CLI took in Flask that I use to create dummy data. It works fine on my local machine but not on Heroku. Here's a terminal session:
(venv) $ flask create-dummy-data
(venv) $ git push staging master
Everything up-to-date
(venv) $ heroku run bash --remote staging
Running bash on ⬢ app-name... up, run.8533 (Free)
~ $ flask create-dummy-data
Usage: flask [OPTIONS] COMMAND [ARGS]...
Try "flask --help" for help.
Error: No such command "create-dummy-data".
Here's my app/cli.py file:
import lorem
from app import db
from app.models import Survey, Question, Option, Answer, Response
def register(app):
#app.cli.command()
def create_dummy_data():
"""Create lorem ipsum questions and answers for testing."""
survey = Survey()
db.session.add(survey)
for _ in range(3):
question = Question(survey=survey, category='likert', question=lorem.sentence())
db.session.add(question)
for _ in range (2):
question = Question(survey=survey, category='word', question=lorem.sentence())
db.session.add(question)
db.session.commit()
And my run.py file:
from app import create_app, db, cli
from app.models import Survey, Question, Option, Answer, Response
app = create_app()
cli.register(app)
#app.shell_context_processor
def make_shell_context():
return {'db': db,
'Survey': Survey,
'Question': Question,
'Option': Option,
'Answer': Answer,
'Response': Response
}
Why would this work locally but not on the Heroku shell?

It was the simplest thing: Heroku didn't have $FLASK_APP set in the staging environment's variables. Adding that allowed the command line tool to run.

Related

Deploying Python Telegram Bot on Heroku

I am trying to deploy my python telegram bot on heroku. Everything builds fine and heroku said its deployed successfully. However, when I tried the bot in telegram, it does not work. I have attached the deployment code below. Can someone help please? Thanks. My Procfile contains this: web: python3 encouragements.py
`import os
TOKEN = "Token"
PORT = int(os.environ.get('PORT', '5000'))
updater = Updater("Token")
updater.start_webhook(listen="0.0.0.0",
port=PORT,
url_path="Token")
updater.bot.setWebhook("https://xxx.herokuapp.com/" + "Token")
updater.idle()`
I found this article helpful when deploying a Telegram bot on Heroku: Creating Telegram Bot and Deploying it to Heroku (make sure the code is up to date by comparing it to the docs guide to Version 12.0)
Based on the article provided above, I've tried to reproduce your case with the following setup:
encouragements.py:
from telegram.ext import Updater, CommandHandler, CallbackContext
from telegram import Update
import os
TOKEN = ""
HEROKU_APP_NAME=""
# def run(updater):
# updater.start_polling()
def run(updater):
PORT = int(os.environ.get("PORT", "8443"))
updater.start_webhook(listen="0.0.0.0",
port=PORT,
url_path=TOKEN)
updater.bot.set_webhook("https://{}.herokuapp.com/{}".format(HEROKU_APP_NAME, TOKEN))
def start_handler(update: Update, context: CallbackContext):
update.message.reply_text("Hello from Python!\nPress /random to get random number")
if __name__ == '__main__':
updater = Updater(TOKEN, use_context=True)
updater.dispatcher.add_handler(CommandHandler("start", start_handler))
run(updater)
Pipfile:
[[source]]
name = "pypi"
url = "https://pypi.org/simple"
verify_ssl = true
[dev-packages]
[packages]
python-telegram-bot = "*"
[requires]
python_version = "3.7"
Procfile:
web: python encouragements.py
And telegram bot is indeed responding to /start message. I followed this article when deploying to Heroku: https://devcenter.heroku.com/articles/getting-started-with-nodejs
I would also recommend to check what is happening on Heroku's side:
heroku logs -t --app <your-heroku-app-name>
Logs should tell you if your token is in fact correct, if your dependencies where properly loaded, and if your code does not produce any error during runtime.
Let me know if it worked :)

DATABASE_URL Heroku key error

I enter the following code to connect to my heroku database using Python:
urlparse.uses_netloc.append("postgres")
url = urlparse.urlparse(os.environ["DATABASE_URL"])
conn = psycopg2.connect(
database=rul.pat[1:],
user=url.username,
password=url.password,
host=url.hostname,
port=url.port
)
I get a key error on the second line. Can someone describe what is happening? Do I need to add the DATABASE_URL to the environment somehow? I am running the Linux bash on Windows 10.
I found the answer here:
KeyError: 'DATABASE_URL' in django 1.4
in the terminal I typed something like this:
export DATABASE_URL=<url to database>

Flask with MongoDB using MongoKit to MongoLabs

I am a beginner and I have a simple application I have developed locally which uses mongodb with mongoKit as follows:
app = Flask(__name__)
app.config.from_object(__name__)
customerDB = MongoKit(app)
customerDB.register([CustomerModel])
then in views I just use the CustomerDB
I have put everything on heroku cloud but my database connection doesn't work.
I got the link I need to connect by:
heroku config | grep MONGOLAB_URI
but I am not sure how to pull this. I looked at the following post, but I am more confused
How can I use the mongolab add-on to Heroku from python?
Any help would be appreciated.
Thanks!
According to the documentation, Flask-MongoKit supports a set of configuration settings.
MONGODB_DATABASE
MONGODB_HOST
MONGODB_PORT
MONGODB_USERNAME
MONGODB_PASSWORD
The MONGOLAB_URI environment setting needs to be parsed to get each of these. We can use this answer to the question you linked to as a starting point.
import os
from urlparse import urlsplit
from flask import Flask
from flask_mongokit import MongoKit
app = Flask(__name__)
# Get the URL from the Heroku setting.
url = os.environ.get('MONGOLAB_URI', 'mongodb://localhost:27017/some_db_name')
# Parse it.
parsed - urlsplit(url)
# The database name comes from the path, minus the leading /.
app.config['MONGODB_DATABASE'] = parsed.path[1:]
if '#' in parsed.netloc:
# If there are authentication details, split the network locality.
auth, server = parsed.netloc.split('#')
# The username and password are in the first part, separated by a :.
app.config['MONGODB_USERNAME'], app.config['MONGODB_PASSWORD'] = auth.split(':')
else:
# Otherwise the whole thing is the host and port.
server = parsed.netloc
# Split whatever version of netloc we have left to get the host and port.
app.config['MONGODB_HOST'], app.config['MONGODB_PORT'] = server.split(':')
customerDB = MongoKit(app)

How to set Heroku config var with contents of a file

To set config vars for a Heroku app, you do this:
$ heroku config:set GITHUB_USERNAME=joesmith
How would I set a config var with the contents of a file?
Take a look at the heroku-config plugin, which adds a heroku config:push command to push key-value pairs in a file named .env to the app.
It also has a heroku config:pull command to do the opposite and works very well with foreman for running the app locally with the config in .env.
https://github.com/xavdid/heroku-config
Example
heroku config:push --file=.env.production
I know this is too late but still it will be helpful for future users who land here.
I also wanted a quick solution to add variable to heroku app but copy-paste is so boring.. So wrote a script to read values from the .env file and set it at the requested app - all things passed as an option:
https://gist.github.com/md-farhan-memon/e90e30cc0d67d0a0cd7779d6adfe62d1
Usage
./bulk_add_heroku_config_variables.sh -f='/path/to/your/.environment/file' -s='bsc-server-name' -k='YOUR_CONFIG_KEY1 YOUR_CONFIG_KEY2'
A simple pure-python solution using honcho and invoke:
from honcho.environ import parse
from invoke import run
def push_env(file='.env'):
"""Push .env key/value pairs to heroku"""
with open(file, 'r') as f:
env = parse(f.read())
cmd = 'heroku config:set ' + ' '.join(
f'{key}={value}' for key, value in env.items())
run(cmd)
The idea here is that you will get the same configuration as if you ran the project locally using honcho. Then I use invoke to run this task easily from the command line (using #task and c.run) but I've adapted it here to stand alone.

gevent-socketio + Flask + Gunicorn

Can I use gevent-socketio with Flask, running under Gunicorn, and still enjoy the nice exception printing, debugger, and reload capability that Flask offers? How would my gunicorn worker and WSGI app class look like?
I've got the exact same problem so I solved it by using watchdog.
pip install watchdog
together with this command:
watchmedo shell-command --patterns="*.py*;;*.less;*.css;*.js;*.txt;*.html" --recursive --command='kill -HUP `cat /tmp/gunicorn.pid` && echo "Reloading code" >> /tmp/gunicorn.log' ~/projectfolder
It requires (well, not really, but I point "Reloading code" into the same logfile so It's a nice thing to have) that you daemonize the gunicorn process, which I do like this:
gunicorn_config.py
workers = 2
worker_class = 'socketio.sgunicorn.GeventSocketIOWorker'
bind = '0.0.0.0:5000'
pidfile = '/tmp/gunicorn.pid'
debug = True
loglevel = 'debug'
errorlog = '/tmp/gunicorn.log'
daemon = True
Start the application:
gunicorn run:app -c gunicorn-config.py
View the log:
tail -f /tmp/gunicorn.log
From this point everything should be reloaded with each change in your project.
It's a bit complicated but since gunicorn with a worker (or the built in socketio-server) doesn't have any reloading capabilities I had to do it like this.
It's a different approach compared to the decorator solution in the other answer but I like to keep the actual code clean from development specific solutions. Both accomplish the same thing so I guess you'll just have to pick the solution you like. :)
Oh, as an added bonus you get to use the production server in development which means both environments match each other.
I've been looking into this subject lately. I don't think you can easily use autoreload feature with Flask + gevent-socket.io + Gunicorn. Gunicorn is a production server that does not allow such features natively.
However, I found a nice solution for my development server : user SocketIOServer provided with the library and a Flask snippet for autoreload. Here is the startup script (runserver.py) :
from myapp import app
from gevent import monkey
from socketio.server import SocketIOServer
import werkzeug.serving
# necessary for autoreload (at least)
monkey.patch_all()
PORT = 5000
#werkzeug.serving.run_with_reloader
def runServer():
print 'Listening on %s...' % PORT
ws = SocketIOServer(('0.0.0.0', PORT), app, resource="socket.io", policy_server=False)
ws.serve_forever()
runServer()
This solution is inspired from : http://flask.pocoo.org/snippets/34/
I've made some tweaks to Werkzeug debugger so it now works with socket.io namespaces, see below and enjoy :)
https://github.com/aldanor/SocketIO-Flask-Debug

Resources