Failed to find application object 'app' in 'main' - Heroku CLI - heroku

I try to push code from this GitHub repo to my Heroku application, but I keep getting the same error, and my process keeps exiting with error 1. I've looked at these posts to solve my problems:
gunicorn causing errors in heroku
Flask app dont start on heroku server
Python Flask heroku application error
main.py
import os
import sys
import urllib.request
import requests
from urllib.parse import urljoin
from bs4 import BeautifulSoup
from flask import Flask, render_template, request, redirect
ic = Flask(__name__)
count = 0
#ic.route("/")
def main():
if count == 1:
return render_template("index.html", result=str((str(count) + " Image Downloaded !")))
else:
return render_template("index.html", result=str((str(count) + " Images Downloaded !")))
#ic.route("/get_images", methods=['POST'])
def get_images():
_url = request.form['inputURL']
try:
global count
count = 0
code = requests.get(_url)
text = code.text
soup = BeautifulSoup(text)
for img in soup.findAll('img'):
count += 1
if (img.get('src'))[0:4] == 'http':
src = img.get('src')
else:
src = urljoin(_url, img.get('src'))
download_image(src, count)
return redirect("http://localhost:5000")
except requests.exceptions.HTTPError as error:
return render_template("index.html", result=str(error))
def download_image(url, num):
try:
image_name = str(num) + ".jpg"
image_path = os.path.join("images/", image_name)
urllib.request.urlretrieve(url, image_path)
except ValueError:
print("Invalid URL !")
except:
print("Unknown Exception" + str(sys.exc_info()[0]))
if __name__ == "__main__":
ic.run()
Procfile
heroku ps:scale web=1
web: gunicorn main:app

When you run
gunicorn main:app
you're telling gunicorn that your application's entry point is the app variable in th main module. You don't have an app variable; your Flask app is called ic.
You also don't need that heroku ps:scale web=1 line. That's a command that you might run on your local machine to scale your web process type to one dyno.
Change your Procfile to say
web: gunicorn main:ic
commit and redeploy.

Related

How to get rid of the error of keep_alive?

from keep_alive import keep_alive
with error
Import "keep_alive" could not be resolved
same directory, have the keep alive file
anyone help me?
basically how do do keep alive
from flask import Flask
from threading import Thread
app = Flask('')
app.route('/')
def main():
return "Bot is online."
def run():
app.run(host = "0.0.0.0", port = 8000)
def keep_alive():
server = Thread(target = run)
server.start()
This is what the keep_alive file contains, and name it like host.py or something. If you are naming it host.py then in your main.py you should add this too.
from host import keep_alive
keep_alive() #added at the bottom after all commands

Python Telegram bot on Heroku can't access Google Spreadsheet

I am deplying a python program on Heroku. Everything works fine locally, but it doesn't seem to run on Heroku
The bot.py file contains two variables which are saved as config in Heroku: TOKEN and SPREADSHEET, these are the Token of the telegram bot and the ID of the google Spreadsheet I am trying to access.
When the code is running on Heroku, I get this:
The code seems to be running on the Heroku server, but when I try to send the command on the Telegram bot, it doesn't work
at=info method=POST path="/" host=fff-transparency-wg.herokuapp.com request_id=d883bfc2-24a3-4cb5-b638-36b310726780 fwd="91.108.6.81" dyno=web.1 connect=1ms service=5ms status=200 bytes=172 protocol=https
The program contains the files:
bot.py
client_secret.json
Procfile
requirements.txt
runtime.txt
BOT.PY
from telegram.ext import Updater, CommandHandler, CallbackQueryHandler
from telegram import InlineKeyboardButton, InlineKeyboardMarkup
import logging
import os
import json
import gspread
from oauth2client.service_account import ServiceAccountCredentials
from datetime import datetime
from itertools import permutations
import re
logging.basicConfig(
format='%(asctime)s - %(name)s - %(levelname)s - %(message)s', level=logging.INFO)
logger = logging.getLogger("telegram.bot")
def start(update, context):
context.bot.send_message(
chat_id=update.effective_chat.id, text="I'm a bot, please talk to me!")
# def help(update, context):
def call(update, context):
"""
Save Message ID, Title, Date, Time, Duration, Description, Link, Group ID, Group name, Saved by Name, Username
Expected inputs (in order): Date, Time, Duration, Title, Description, Link
Send variables to Google Sheet
Send variables to Trello Board
Send variables to Google Calendar
OPTIONAL:
Notification System
"""
message_id = update.message.message_id
user = update.message.from_user
username = user['username']
full_name = "{} {}".format(user['first_name'], user['last_name'])
groupchat = update.message.chat
message_text = update.message.text
text = format_string(message_text, "/call")
if (text == -1):
groupchat.send_message(
text="Please make sure all arguments are inserted in the correct order and separated by semicolomns:\n\n- Date (dd/mm/yy) \n- Time (GMT) \n- Duration (hour:min) \n- Title \n- Description(optional) \n- Agenda Link(optional)")
call_date = text[0]
call_time = text[1]
call_duration = text[2]
call_title = text[3]
#if text[4]: call_description = text[4]
#if text[5]: call_agenda = text[5]
calls.append_row(
[message_id, call_title, call_date, call_time, call_duration])
# def group(update, context):
def str2date(string):
"Parse a string into a datetime object."
for fmt in dateformats():
try:
return datetime.strptime(string, fmt)
except ValueError:
pass
raise ValueError("'%s' is not a recognized date/time" % string)
def format_string(message, command):
message = re.sub(command, '', message)
message.strip()
message = message.split(';')
if not(len(message) >= 4):
return -1
if command == "/call":
message[0: 1] = [' '.join(message[0: 1])]
s = message[0].strip()
try:
message[0] = str2date(s)
except ValueError:
print("invalid date/time")
return message
def dateformats():
"Yield all combinations of valid date formats."
years = ("%Y",)
months = ("%b", "%B")
days = ("%d",)
times = ("%I%p", "%I:%M%p", "%H:%M", "")
for year in years:
for month in months:
for day in days:
for args in ((day, month), (month, day)):
date = " ".join(args)
for time in times:
for combo in permutations([year, date, time]):
yield " ".join(combo).strip()
def error(update, context):
logger.warning('Update "%s" caused error "%s"', update, context.error)
def main():
TOKEN = os.environ['TOKEN']
updater = Updater(token=TOKEN, use_context=True)
dp = updater.dispatcher
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://fff-transparency-wg.herokuapp.com/" + TOKEN)
updater.idle()
# use creds to create a client to interact with the Google Drive API
scope = ['https://spreadsheets.google.com/feeds', 'https://www.googleapis.com/auth/drive', 'https://www.googleapis.com/auth/drive.file', 'https://www.googleapis.com/auth/drive']
creds = ServiceAccountCredentials.from_json_keyfile_name(
'client_secret.json', scope)
client = gspread.authorize(creds)
# Find a workbook by name and open the first sheet
SPREADSHEET = os.environ['SPREADSHEET']
spreadsheet = client.open_by_key(
SPREADSHEET)
groupchats = spreadsheet.get_worksheet(0)
calls = spreadsheet.get_worksheet(1)
# Commands
dp.add_handler(CommandHandler("start", start))
#dp.add_handler(CommandHandler("help", help))
dp.add_handler(CommandHandler("call", call))
#dp.add_handler(CommandHandler("group", group))
dp.add_error_handler(error)
if __name__ == '__main__':
main()
PROCFILE
web: python3 bot.py
worker: python3 bot.py
REQUIREMENTS.TXT
certifi==2019.11.28
cffi==1.14.0
chardet==3.0.4
cryptography==2.9
decorator==4.4.2
future==0.18.2
gspread==3.3.1
httplib2==0.17.1
idna==2.9
oauth2client==4.1.3
pyasn1==0.4.8
pyasn1-modules==0.2.8
pycparser==2.20
python-telegram-bot==12.5.1
requests==2.23.0
rsa==4.0
six==1.14.0
tornado==6.0.4
urllib3==1.25.8
RUNTIME.TXT
python-3.8.2
I had the same issue with my telegram bot.
I added the actual bot token string to the TOKEN variable and uploaded it to Heroku.
Then I used os.environ.get('TOKEN') command for the version that I pushed on GitHub.
I am still just a beginner in python, I don't know if this posses security issues but it removed the error code and allowed my bot to work

flask server running in virtual box is not accessible from the windows host

I have tried running it from host='0.0.0.0' and it is still inaccessible. I can ping my windows machine ip 192.168.1.109 from my virtualmachine, but I can not ping my Ubuntu VirtualMachine ip from ifconfig 10.0.2.15 from my windows side. I am using virtualbox if that helps.
run.py
#!flask/bin/python
from app import app
app.run(host='0.0.0.0',port=5000, debug=True)
init.py
import os
from flask import Flask
from flask.json import JSONEncoder
from flask_sqlalchemy import SQLAlchemy
from flask_login import LoginManager
from flask_mail import Mail
from flask_babel import Babel, lazy_gettext
from config import basedir, ADMINS, MAIL_SERVER, MAIL_PORT, MAIL_USERNAME, \
MAIL_PASSWORD
from .momentjs import momentjs
app = Flask(__name__)
app.config.from_object('config')
db = SQLAlchemy(app)
lm = LoginManager()
lm.init_app(app)
lm.login_view = 'login'
lm.login_message = lazy_gettext('Please log in to access this page.')
mail = Mail(app)
babel = Babel(app)
class CustomJSONEncoder(JSONEncoder):
"""This class adds support for lazy translation texts to Flask's
JSON encoder. This is necessary when flashing translated texts."""
def default(self, obj):
from speaklater import is_lazy_string
if is_lazy_string(obj):
try:
return unicode(obj) # python 2
except NameError:
return str(obj) # python 3
return super(CustomJSONEncoder, self).default(obj)
app.json_encoder = CustomJSONEncoder
if not app.debug and MAIL_SERVER != '':
import logging
from logging.handlers import SMTPHandler
credentials = None
if MAIL_USERNAME or MAIL_PASSWORD:
credentials = (MAIL_USERNAME, MAIL_PASSWORD)
mail_handler = SMTPHandler((MAIL_SERVER, MAIL_PORT),
'no-reply#' + MAIL_SERVER, ADMINS,
'microblog failure', credentials)
mail_handler.setLevel(logging.ERROR)
app.logger.addHandler(mail_handler)
if not app.debug and os.environ.get('HEROKU') is None:
import logging
from logging.handlers import RotatingFileHandler
file_handler = RotatingFileHandler('tmp/microblog.log', 'a',
1 * 1024 * 1024, 10)
file_handler.setLevel(logging.INFO)
file_handler.setFormatter(logging.Formatter(
'%(asctime)s %(levelname)s: %(message)s [in %(pathname)s:%(lineno)d]'))
app.logger.addHandler(file_handler)
app.logger.setLevel(logging.INFO)
app.logger.info('microblog startup')
if os.environ.get('HEROKU') is not None:
import logging
stream_handler = logging.StreamHandler()
app.logger.addHandler(stream_handler)
app.logger.setLevel(logging.INFO)
app.logger.info('microblog startup')
app.jinja_env.globals['momentjs'] = momentjs
from app import views, models
It worked for me when I changed this line in the main
app.run()
to
app.run(host='192.168.163.128', port=5000)

send data from celery to tornado websocket

I have some periodic tasks which I execute with Celery (parse pages).
Also I established a websocket with tornado.
I want to pass data from periodic tasks to tornado, then write this data to websocket and use this data on my html page.
How can I do this?
I tried to import module with tornado websocket from my module with celery tasks, but ofcourse, that didn't work.
I know only how to return some data, if I get a message from my client-side. Here is how I cope with it:
import tornado.httpserver
import tornado.websocket
import tornado.ioloop
import tornado.web
import socket
'''
This is a simple Websocket Echo server that uses the Tornado websocket handler.
Please run `pip install tornado` with python of version 2.7.9 or greater to install tornado.
This program will echo back the reverse of whatever it recieves.
Messages are output to the terminal for debuggin purposes.
'''
class handler():
wss = []
class WSHandler(tornado.websocket.WebSocketHandler):
def open(self):
print ('new connection')
if self not in handler.wss:
handler.wss.append(self)
def on_message(self, message):
print ('message received: ' + message)
wssend('Ihaaaa')
def on_close(self):
print ('connection closed')
if self in handler.wss:
handler.wss.remove(self)
def check_origin(self, origin):
return True
def wssend(message):
print(handler.wss)
for ws in handler.wss:
if not ws.ws_connection.stream.socket:
print ("Web socket does not exist anymore!!!")
handler.wss.remove(ws)
else:
print('I am trying!')
ws.write_message(message)
print('tried')
application = tornado.web.Application([
(r'/ws', WSHandler),
])
if __name__ == "__main__":
http_server = tornado.httpserver.HTTPServer(application)
http_server.listen(8888)
myIP = socket.gethostbyname(socket.gethostname())
print ('*** Websocket Server Started at %s***' % myIP)
main_loop = tornado.ioloop.IOLoop.instance()
main_loop.start()
The option is to make a handle in tornado and then post results of celery task to this handle.
After that, there will be an opportunity to pass this data to websocket.

How use Django with Tornado web server?

How do I use Django with the Tornado web server?
it's very simple ( especially with django 1.4) .
1 - just build your django project( and apps ) and make sure it works fine.
2- create a new python file at the root folder ( same dir where you used django-admin.py startproject)
3- then copy the code below , edit the os.environ['DJANGO_SETTINGS_MODULE'] line, and paste it in that new .py file.
import os
import tornado.httpserver
import tornado.ioloop
import tornado.wsgi
import sys
import django.core.handlers.wsgi
#sys.path.append('/home/lawgon/') # path to your project ( if you have it in another dir).
def main():
os.environ['DJANGO_SETTINGS_MODULE'] = 'myProject.settings' # path to your settings module
application = django.core.handlers.wsgi.WSGIHandler()
container = tornado.wsgi.WSGIContainer(application)
http_server = tornado.httpserver.HTTPServer(container)
http_server.listen(8888)
tornado.ioloop.IOLoop.instance().start()
if __name__ == "__main__":
main()
Django 1.6+ it should be like this:
import os
import tornado.httpserver
import tornado.ioloop
import tornado.wsgi
from django.core.wsgi import get_wsgi_application
def main():
os.environ['DJANGO_SETTINGS_MODULE'] = 'myproject.settings' # path to your settings module
application = get_wsgi_application()
container = tornado.wsgi.WSGIContainer(application)
http_server = tornado.httpserver.HTTPServer(container)
http_server.listen(8888)
tornado.ioloop.IOLoop.instance().start()
if __name__ == "__main__":
main()
UPDATE:
I created a minimal working demo which shows how to use the Tornado web server to run nicely with django:
https://github.com/tamasgal/django-tornado
ORIGINAL POST:
Just a remark: The WSGI application workflow has been changed from 1.6 to 1.7. You have to replace the import
import django.core.handlers.wsgi
with
from django.core.wsgi import get_wsgi_application
and change the application initialisation from
application = django.core.handlers.wsgi.WSGIHandler()
to
application = get_wsgi_application()
This is the modified code from the Moayyad Yaghi's answer:
import os
import tornado.httpserver
import tornado.ioloop
import tornado.wsgi
import sys
import django.core.handlers.wsgi
from django.core.wsgi import get_wsgi_application
#sys.path.append('/home/lawgon/') # path to your project ( if you have it in another dir).
def main():
os.environ['DJANGO_SETTINGS_MODULE'] = 'myProject.settings' # path to your settings module
application = django.core.handlers.wsgi.WSGIHandler()
application = get_wsgi_application()
container = tornado.wsgi.WSGIContainer(application)
http_server = tornado.httpserver.HTTPServer(container)
http_server.listen(8888)
tornado.ioloop.IOLoop.instance().start()
if __name__ == "__main__":
main()
There's a project called tornado-proxy that would help you. But I would like to recommend that you use Nginx. In the Nginx config you could now use proxy_pass to direct your calls like this:
location /comet {
proxy_pass http://localhost:8081;
}
location / {
proxy_pass http://localhost:8080;
}
In real world you would connect Django and some production-ready webserver with WSGI. This demo shows how you can run Tornado (and it's webserver) and Django side by side from one python module serving different URL prefixes: https://github.com/bdarnell/django-tornado-demo.
Tornado would block on serving any request directed to Django, though.

Resources