Flask heroku app won't let me assign some config settings - flask

I have a flask MySql app that is working correctly on local, but when I deployed to heroku it gives me below error:
2022-02-12T05:28:26.114583+00:00 app[web.1]: File "/app/app.py", line 38, in <module>
2022-02-12T05:28:26.114583+00:00 app[web.1]: app.config['SQLALCHEMY_TRACK_MODIFICATIONS'] = False
2022-02-12T05:28:26.114584+00:00 app[web.1]: TypeError: 'str' object does not support item assignment
It did the same thing when I used app.debug = False. I tried to fix it my removing it, but now it gives me above error.
I tried commenting each line that gives error and looks like all below lines give the same error:
app.config['SQLALCHEMY_TRACK_MODIFICATIONS'] = False
app.config['SESSION_PERMANENT'] = False
app.config['SESSION_TYPE'] = "filesystem"
Few lines before these lines I have app.config['MAIL_USE_SSL'] = True and some other mail config settings (port, server, username, password) which none of them give error, so I don't understand what the problem is. When I google the error it is related with the immutability of strings, so I don't understand what is the problem on my case.
When I comment all of the above it gives me:
2022-02-12T08:11:34.109191+00:00 app[web.1]: Session(app)
2022-02-12T08:11:34.109196+00:00 app[web.1]: File "/app/.heroku/python/lib/python3.8/site-packages/flask_session/__init__.py", line 54, in __init__
2022-02-12T08:11:34.109196+00:00 app[web.1]: self.init_app(app)
2022-02-12T08:11:34.109196+00:00 app[web.1]: File "/app/.heroku/python/lib/python3.8/site-packages/flask_session/__init__.py", line 61, in init_app
2022-02-12T08:11:34.109197+00:00 app[web.1]: app.session_interface = self._get_interface(app)
2022-02-12T08:11:34.109197+00:00 app[web.1]: File "/app/.heroku/python/lib/python3.8/site-packages/flask_session/__init__.py", line 64, in _get_interface
2022-02-12T08:11:34.109197+00:00 app[web.1]: config = app.config.copy()
2022-02-12T08:11:34.109198+00:00 app[web.1]: AttributeError: 'str' object has no attribute 'copy'
I'm using JawsDB MySQL addon on heroku if that is related with this issue.
Below is the code:
from flask import Flask
from flask_mail import Mail
from os import environ
from flask_session import Session
from flask_cors import CORS
from flask_sqlalchemy import SQLAlchemy
app = Flask(__name__)
app.config['MAIL_SERVER'] = 'smtp.domain.com'
app.config['MAIL_PORT'] = 465
app.config['MAIL_USE_SSL'] = True
app.config['MAIL_USERNAME'] = "mail#domain.com"
app.config['MAIL_PASSWORD'] = environ.get("MAIL_PASSWORD")
mail = Mail(app)
MY_APP_ENV = environ.get("MY_APP_ENV")
if MY_APP_ENV == 'prod':
app.debug = False
app.config = environ.get("JAWSDB_URL")
else:
app.debug = True
app.config['SQLALCHEMY_DATABASE_URI'] = 'mysql://root:#localhost/my_app'
app.config['SQLALCHEMY_TRACK_MODIFICATIONS'] = False
app.config['SESSION_PERMANENT'] = False
app.config['SESSION_TYPE'] = "filesystem"
Session(app)
CORS(app)
db = SQLAlchemy(app)
# rest is the routings etc.

Here's the problem:
app.config = environ.get("JAWSDB_URL")
You are overwriting app.config with a single value from the environment.
Do you mean something like this instead?
app.config["SQLALCHEMY_DATABASE_URI"] = environ.get("JAWSDB_URL")

Related

Is there a way could deploy Django project on namecheap in ASGI mode?

I'm trying to deploy my Django on Namecheap, the server should work but I got the following message traceback:
[ERROR] [UID:12123][2655752] wsgiAppHandler pApp->start_response() return NULL.
Traceback (most recent call last):
File "/home/alshigpf/website/passenger_wsgi.py", line 41, in __call__
return self.app(environ, start_response)
TypeError: __call__() missing 1 required positional argument: 'send'
[ERROR] [UID:12123][2655752] wsgiAppHandler pApp->start_response() return NULL.
Traceback (most recent call last):
File "/home/alshigpf/website/passenger_wsgi.py", line 41, in __call__
return self.app(environ, start_response)
TypeError: __call__() missing 1 required positional argument: 'send'
This is what my passenger_wsgi.py file looks like:
import os
import sys
import django
sys.path.append(os.getcwd())
os.environ['DJANGO_SETTINGS_MODULE'] = 'website.settings.development'
django.setup()
SCRIPT_NAME = os.getcwd()
print("Script name: ", SCRIPT_NAME)
class PassengerPathInfoFix(object):
"""
Sets PATH_INFO from REQUEST_URI because Passenger doesn't provide it.
"""
def __init__(self, app):
self.app = app
print("Start Init")
print("App is: ", self.app)
print("End Init")
def __call__(self, environ, start_response):
from urllib.parse import unquote
print("Start Calling")
environ['SCRIPT_NAME'] = SCRIPT_NAME
request_uri = unquote(environ['REQUEST_URI'])
script_name = unquote(environ.get('SCRIPT_NAME', ''))
offset = request_uri.startswith(script_name) and len(environ['SCRIPT_NAME']) or 0
environ['PATH_INFO'] = request_uri[offset:].split('?', 1)[0]
return self.app(environ, start_response)
# Get ASGI application
from website.routing import application
print("Before calling application")
application = PassengerPathInfoFix(application)
when I googled I glanced that there's something called "Uvicorn" which is an updated version of Gunicorn to handle ASGI mode.
when I did an advanced search on google to see if namecheap.com talk about using uvicorn I didn't find anything related to this problem.
so, my question is: how can I ignore this issue by still using ASGI mode instead of WSGI?

How to use oidc (OpenIDConnect object) in flask.Blueprint when using flask.create_app?

I want to use #oidc.require_login to redirect login request to okta. I get AttributeError: '_AppCtxGlobals' object has no attribute 'oidc_id_token' error which I am unable to resolve
1) I built an app based on Flaskr tutorial that demonstrates use of flask factory method create_app.
2) I created a okta.py class as follows:
from oauth2client.client import OAuth2Credentials
from flask_oidc import OpenIDConnect
from okta import UsersClient
import click
from flask import current_app, g, session
from flask.cli import with_appcontext
oidc = OpenIDConnect()
def get_oidc():
"""
Connect to okta
"""
if 'oidc' not in g:
print('okta: get_oidc call')
g.oidc = OpenIDConnect(current_app)
g.okta_client = UsersClient("<okta-server-url>", "<secret>")
# fixing global oidc problem for decorator in rooms
oidc = g.oidc
return g.oidc
def close_oidc(app):
""" Release okta connection
"""
oidc = g.pop('oidc',None)
if oidc is not None:
oidc.logout()
# with app.app_context():
# session.clear()
def init_okta():
"""Connect to existing table"""
oidc = get_oidc()
""" Can do additional initialization if required """
#click.command('init-okta')
#with_appcontext
def init_okta_command():
"""Connect to existing oidc"""
init_okta()
click.echo (get_oidc())
click.echo('Initialized Okta.')
print('Initialized Okta.')
def init_app(app):
"""Register okta functions with the Flask app. This is called by
the application factory.
"""
app.teardown_appcontext(close_oidc)
app.cli.add_command(init_okta_command)
3) My goal is to use okta login to browse room listings
from flask import (
Blueprint, flash, g, redirect, render_template,
request, url_for, current_app, session, jsonify
)
from werkzeug.exceptions import abort
...
from hotel.okta import oidc, get_oidc, init_app
bp = Blueprint('rooms', __name__)
...
#bp.route('/login', methods=['GET', 'POST'])
#oidc.require_login
def login():
"""
Force the user to login, then redirect them to the get_books.
Currently this code DOES NOT work
Problem:
* oidc global object is not available to pass request to okta
Resolution:
* redirecting to rooms.calendar
"""
# info = oidc.user_getinfo(['preferred_username', 'email', 'sub'])
# id_token = OAuth2Credentials.from_json(oidc.credentials_store[info.get('sub')]).token_response['id_token']
return redirect(url_for("rooms.calendar"))
4) My __init__.py looks like this
import os
from flask import Flask
from flask_oidc import OpenIDConnect
from okta import UsersClient
# This is a factory method for productive deployment
# Use app specific configuration
# For any app local files, use /instnce Folder
def create_app(test_config=None):
"""Create and configure an instance of the Flask application."""
app = Flask(__name__, instance_relative_config=True)
app.config.from_mapping(
# a default secret that should be overridden by instance config
SECRET_KEY='dev',
# store the database in the instance folder
DATABASE=os.path.join(app.instance_path, 'hotel.sqlite'),
OIDC_CLIENT_SECRETS=os.path.join(app.instance_path, 'client_secrets.json'),
OIDC_COOKIE_SECURE=False,
OIDC_CALLBACK_ROUTE= '/oidc/callback',
OIDC_SCOPES=["openid", "email", "profile"],
OIDC_ID_TOKEN_COOKIE_NAME = 'oidc_token',
)
if test_config is None:
# load the instance config, if it exists, when not testing
app.config.from_pyfile('config.py', silent=True)
else:
# load the test config if passed in
app.config.update(test_config)
# ensure the instance folder exists
try:
os.makedirs(app.instance_path)
except OSError:
pass
# # register the database commands
from hotel import db
db.init_app(app)
# apply the blueprints to the app
from hotel import rooms
app.register_blueprint(rooms.bp)
# for Okta
# Ref: https://www.fullstackpython.com/blog/add-user-authentication-flask-apps-okta.html
from hotel import okta
with app.app_context():
okta.init_app(app)
#app.route('/hello') # For testing factory method
def hello():
return 'Hello, World!'
# make url_for('index') == url_for('blog.index')
# in another app, you might define a separate main index here with
# app.route, while giving the blog blueprint a url_prefix, but for
# the tutorial the blog will be the main index
app.add_url_rule('/', endpoint='index')
return app
5) Here is the code snippet of rooms.before_request
#bp.before_request
def before_request():
print ('rooms.before_request call reached')
with current_app.app_context():
print ('rooms.before_request in app_context',g)
oidc = g.pop('oidc',None)
okta_client = g.pop('okta_client',None)
if oidc is not None and okta_client is not None:
print ('rooms.before_request g.oidc and g.okta_client available')
if oidc.user_loggedin:
# OpenID Token as
g.user = okta_client.get_user(oidc.user_getfield("sub"))
g.oidc_id_token = OAuth2Credentials.from_json(g.oidc.credentials_store[info.get('sub')]).token_response['id_token']
else:
g.user = None
else:
print('rooms.beforerequest No user logged in')
g.user = None
My Analysis:
okta.init_app(app) is expected to use client_secrets.json in /instance folder to connect to okta.
In order to make #oidc.require_login to work, I exposed oidc in okta.get_oidc and import this into my rooms.py code
However, this does not work :(! Stack trace is:
File "/Users/athur/Code/cmpe272WarriorsHotel/Hotel/venv/lib/python3.7/site-packages/flask/app.py", line 2328, in __call__
return self.wsgi_app(environ, start_response)
File "/Users/athur/Code/cmpe272WarriorsHotel/Hotel/venv/lib/python3.7/site-packages/flask/app.py", line 2314, in wsgi_app
response = self.handle_exception(e)
File "/Users/athur/Code/cmpe272WarriorsHotel/Hotel/venv/lib/python3.7/site-packages/flask/app.py", line 1760, in handle_exception
reraise(exc_type, exc_value, tb)
File "/Users/athur/Code/cmpe272WarriorsHotel/Hotel/venv/lib/python3.7/site-packages/flask/_compat.py", line 36, in reraise
raise value
File "/Users/athur/Code/cmpe272WarriorsHotel/Hotel/venv/lib/python3.7/site-packages/flask/app.py", line 2311, in wsgi_app
response = self.full_dispatch_request()
File "/Users/athur/Code/cmpe272WarriorsHotel/Hotel/venv/lib/python3.7/site-packages/flask/app.py", line 1834, in full_dispatch_request
rv = self.handle_user_exception(e)
File "/Users/athur/Code/cmpe272WarriorsHotel/Hotel/venv/lib/python3.7/site-packages/flask/app.py", line 1737, in handle_user_exception
reraise(exc_type, exc_value, tb)
File "/Users/athur/Code/cmpe272WarriorsHotel/Hotel/venv/lib/python3.7/site-packages/flask/_compat.py", line 36, in reraise
raise value
File "/Users/athur/Code/cmpe272WarriorsHotel/Hotel/venv/lib/python3.7/site-packages/flask/app.py", line 1832, in full_dispatch_request
rv = self.dispatch_request()
File "/Users/athur/Code/cmpe272WarriorsHotel/Hotel/venv/lib/python3.7/site-packages/flask/app.py", line 1818, in dispatch_request
return self.view_functions[rule.endpoint](**req.view_args)
File "/Users/athur/Code/cmpe272WarriorsHotel/Hotel/venv/lib/python3.7/site-packages/flask_oidc/__init__.py", line 485, in decorated
if g.oidc_id_token is None:
File "/Users/athur/Code/cmpe272WarriorsHotel/Hotel/venv/lib/python3.7/site-packages/werkzeug/local.py", line 348, in __getattr__
return getattr(self._get_current_object(), name)
AttributeError: '_AppCtxGlobals' object has no attribute 'oidc_id_token'
My questions:
How can I call #oidc.require_login in flask application factory
method?
Is the way I initialize okta connection correct?
Is there anyway to manually call external authorization server without decorator approach? How?
Is setting flask stack variables a better way to go forward? If so, how?
Trying to set g in before_request does not seem to work. What are the other options to work in Flask's App Factory approach?
Any insights will be much appreciated!
Thanks!
Yuva

Login via Airflow Web Authentication shows an error page

I enabled a Web Authentication for Airflow by following instructions at http://airflow.apache.org/security.html#web-authentication (and restarted the web server)
Logging in seems to work but what I see is an error page with this error message:
File "/usr/local/lib/python2.7/dist-packages/airflow/contrib/auth/backends/password_auth.py", line 154, in login
user = authenticate(session, username, password)
File "/usr/local/lib/python2.7/dist-packages/airflow/contrib/auth/backends/password_auth.py", line 131, in authenticate
if not user.authenticate(password):
File "/usr/local/lib/python2.7/dist-packages/airflow/contrib/auth/backends/password_auth.py", line 72, in authenticate
return check_password_hash(self._password, plaintext)
File "/usr/local/lib/python2.7/dist-packages/flask_bcrypt.py", line 67, in check_password_hash
return Bcrypt().check_password_hash(pw_hash, password)
File "/usr/local/lib/python2.7/dist-packages/flask_bcrypt.py", line 193, in check_password_hash
return safe_str_cmp(bcrypt.hashpw(password, pw_hash), pw_hash)
File "/usr/local/lib/python2.7/dist-packages/bcrypt/__init__.py", line 81, in hashpw
original_salt, salt = salt, _normalize_re.sub(b"$2b$", salt)
TypeError: expected string or buffer
Any idea/insight on this issue?
As mentioned here, using the following worked for me when I had the same error:
import airflow
from airflow import models, settings
from airflow.contrib.auth.backends.password_auth import PasswordUser
from flask_bcrypt import generate_password_hash
user = PasswordUser(models.User())
user.username = 'some'
user.email = 'some#email.com'
user._password = generate_password_hash('password', 12).decode('utf-8')
session = settings.Session()
session.add(user)
session.commit()
session.close()

File writing in Django keeps having IOError

I'm running my app locally and I'm currently having an IOError during my file creation from the database. I am using Django 1.10, MongoDB as my database, and Celery 4.0.2 for my background tasks. The problem occurs in the tasks.py since that is where I access the db then store it in my django subfolder 'analysis_samples'.
Here is the traceback:
[2017-04-15 15:31:08,798: ERROR/PoolWorker-2] Task tasks.process_sample_input[0619194e-4300-4a1d-91b0-20766e048c4a] raised unexpected: IOError(2, 'No such file or directory')
Traceback (most recent call last):
File "/usr/local/lib/python2.7/dist-packages/celery/app/trace.py", line 367, in trace_task
R = retval = fun(*args, **kwargs)
File "/usr/local/lib/python2.7/dist-packages/celery/app/trace.py", line 622, in __protected_call__
return self.run(*args, **kwargs)
File "/home/user/django_apps/myapp/analysis/tasks.py", line 218, in process_sample_input
with open(sample_file_path, "w+") as f:
IOError: [Errno 2] No such file or directory: u'/home/user/django_apps/myapp/myapp/analysis_samples/58f1cc3c45015d127c3d68c1'
And here is the snippet of tasks.py:
from django.core.files import File
sys.path.append(settings.ANALYSIS_SAMPLES)
import base64
import os, sys
#shared_task(name='tasks.process_sample_input')
def process_sample_input(instance_id):
instance = Sample.objects.get(pk=instance_id)
#many code here..
try:
conn=pymongo.MongoClient(settings.MONGO_HOST, settings.MONGO_PORT)
db = conn.thugfs #connect to GridFS db of thug
thugfs_db = GridFS(db)
except pymongo.errors.ConnectionFailure, e:
logger.error("Could not connect to ThugFS MongoDB: %s" % e)
sample_file_folder = settings.ANALYSIS_SAMPLES
for sample_fs_id in sample_fs_ids:
sample_file = thugfs_db.get(ObjectId(sample_fs_id)).read()
sample_file = base64.b64decode(sample_file) #decode file from database
sample_file_path = os.path.join(sample_file_folder, sample_fs_id)
with open(sample_file_path, "w+") as f:
fileOut = File(f)
fileOut.write(sample_file)
settings.py:
ANALYSIS_SAMPLES = os.path.join(BASE_DIR, 'myapp/analysis_samples')
Can anyone see the point that caused the error? Any help will be appreciated.

can't send mails using flask, any ideas?

L.T:
Ok now it works. I had to instantiate Mail() class after configuration(ie. app.config) :)
i have this error:
host = smtplib.SMTP(self.mail.server, self.mail.port)
File "C:\Python27\lib\smtplib.py", line 256, in __init__
(code, msg) = self.connect(host, port)
File "C:\Python27\lib\smtplib.py", line 316, in connect
self.sock = self._get_socket(host, port, self.timeout)
File "C:\Python27\lib\smtplib.py", line 291, in _get_socket
return socket.create_connection((host, port), timeout)
File "C:\Python27\lib\socket.py", line 571, in create_connection
raise err
error: [Errno 10061] No connection could be made because the target machine actively refused it
I'm trying to build a site for myself, and i'm stuck at the part of sending e-mails because of the above error. Thing is i opened my port (that's because i'm behind a router). One thing to note is that using 'standalone' smtplib works but the one from flask doesn't. I'll post what works and does not. I don't know what is the problem. I modified address from socket.py to my 'localhost' and port 465 because i thought that was the problem. Hence i tried almost everything i could but in avail. Could someone help me a little bit here? Thanks.
This doesn't work(hello.py):
from flask import Flask
from flask_mail import Mail
from flask_mail import Message
from flask.ext.script import Manager
import os
mail = Mail()
app = Flask(__name__)
mail.init_app(app)
mail = Mail(app)
manager = Manager(app)
app.config['MAIL_SERVER'] = 'smtp.gmail.com'
app.config['MAIL_PORT'] = 465
app.config['MAIL_USE_SSL'] = True
app.config['MAIL_USERNAME'] = os.environ.get('MAIL_USERNAME')
app.config['MAIL_PASSWORD'] = os.environ.get('MAIL_PASSWORD')
#app.route('/')
def index():
msg = Message('Hello',
sender = 'my_mail#gmail.com',
recipients = ['my_mail#gmail.com'])
msg.body = 'testing'
msg.html = '<b>testing</b>'
mail.send(msg)
app.debug = True
if __name__ == '__main__':
manager.run()
And tried a more minimalist way to see if this works, and it works, i can send mail to myself(mail.py):
import smtplib
from hello import app
gmail_user = app.config['MAIL_USERNAME']
gmail_pwd = app.config['MAIL_PASSWORD']
FROM = 'my_mail#gmail.com'
TO = ['my_mail#gmail.com']
message = 'test'
server_ssl = smtplib.SMTP_SSL("smtp.gmail.com", 465)
server_ssl.ehlo() # optional, called by login()
server_ssl.login(gmail_user, gmail_pwd)
# ssl server doesn't support or need tls, so don't call server_ssl.starttls()
server_ssl.sendmail(FROM, TO, message)
#server_ssl.quit()
server_ssl.close()
print 'successfully sent the mail'
Bump...
It has nothing to do with objects. Functions are designed the way they return a value, and you can assign that value the same way you put the input into the list.
You just run the function, take the value it returned and put it into the variable.