How to pass database session to Ariadne in Fastapi - sqlalchemy

I'm new to python, trying to learn and use Fastapi, Ariadne and SQLAlchemy. I'm following the docs and I'm stuck.
I have my dependency injection get_db() for normal REST requests, which provides a Session object, which I pass through few different modules from the request start until I actually do the db work, and honestly I don't get this design. But I left it there.
Then, another problem come up. How can I pass db to Ariadne GraphQL? Should I use context_value or are there any other options?

You need to create a session of SQLAlchemy from ariadne resolvers. And don't forget to close the connection after resolvers finished.
Let's say your database file like following,
import os
from sqlalchemy import create_engine
from sqlalchemy.orm import sessionmaker
SQLALCHEMY_DATABASE_URL = os.getenv("DB_CONN_STRING")
engine = create_engine(SQLALCHEMY_DATABASE_URL)
LocalSession = sessionmaker(autocommit=False, autoflush=False, bind=engine)
def get_db():
db = None
try:
db = LocalSession()
yield db
finally:
if db:
db.close()
You can do like following on the resolvers
# Import the local session from local database file
from app.database import LocalSession
db = LocalSession()
# Do whatever you need to do
db.close()

Related

Flask Application (MySQL) - KeyError: 'migrate'

In order to perform a migration, through commands flask db init and flask db migrate, I receive the following error: directory = current_app.extensions['migrate'].directory KeyError: 'migrate'.
I have created a Migrate object within my __init__.py file, however, still receive the error stated above:
from flask import Flask
from flask_sqlalchemy import SQLAlchemy
from config import app_config
from flask_login import LoginManager
from flask_migrate import Migrate
# Creating Flask app.
app = Flask(__name__)
# Database variable initialisation.
db = SQLAlchemy()
login_manager = LoginManager()
def create_app(config_name):
app = Flask(__name__, instance_relative_config=True)
app.config.from_object(app_config[config_name])
app.config.from_pyfile('config.py')
db.init_app(app)
# Creating login manager object and initialising it.
# Login view and message prevent a user to accessing a page they are not authorised to.
login_manager.init_app(app)
login_manager.login_message = "Please login to access this page."
login_manager.login_view = "auth.login"
migrate = Migrate(app, db)
from app import models
return app
Any advice for what I am doing wrong? I have already viewed quite a few pages related to this error and have implemented the possible alterations.
I found the problem. The above __init__.py class was completely fine.
My config.py file which contained the following code:
SQLALCHEMY_DATABASE_URI = 'mysql+mysqlconnector://{db_user}:{my_password}#localhost/{database}'
... had a format extension to it which was not needed. I have successfully updated my database.

"from flaskext.mysql import MySQL" causes server to show 502 bad gateway

new to python. Following a couple tutorials to serve an application (ddworkflow.com) using Python 3.6.7, Flask, Gunicorn, NGINX, and MySQL on Ubuntu 18.04
The tutorials are:
https://philchen.com/2019/02/11/how-to-make-a-python-web-app-in-virtualenv-using-flask-gunicorn-nginx-on-ubuntu-18-04
and
https://code.tutsplus.com/tutorials/creating-a-web-app-from-scratch-using-python-flask-and-mysql--cms-22972
I got through the first tutorial and am able to successfully serve the basic web pages from the second tutorial.
Installing everything in a virtual environment and just installed flask-mysql using pip install flask-mysql.
My pip freeze shows:
Click==7.0
Flask==1.0.2
Flask-MySQL==1.4.0
itsdangerous==1.1.0
Jinja2==2.10
MarkupSafe==1.1.0
PyMySQL==0.9.3
Werkzeug==0.14.1
After installing Flask-MySQL I tested the installation by trying the following different variations of the "from" command (at the python prompt):
from flask.ext.mysql import MySQL
from flaskext.mysql import MySQL
from flask_mysql import MySQL
from flaskext.mysql import MySQL
1, 2, and 3 all produce ModuleNotFoundError... The only one that does not throw an error is from flaskext.mysql import MySQL
However, when I add from flaskext.mysql import MySQL to my flask app file (app01.py) I immediately get a 502 bad gateway error. My app01.py file is
from flask import Flask, render_template, json, request
#from flaskext.mysql import MySQL #<--comment out or get 502 error
hello = Flask(__name__)
#hello.route("/")
def greeting():
return render_template('index.html')
#hello.route('/showSignUp')
def showSignUp():
return render_template('signup.html')
#hello.route('/signUp',methods=['POST'])
def signUp():
# read the posted values from the UI
_name = request.form['inputName']
_email = request.form['inputEmail']
_password = request.form['inputPassword']
# validate the received values
if _name and _email and _password:
return json.dumps({'html':'<span>All fields good !!</span>'})
else:
return json.dumps({'html':'<span>Enter the required fields</span>'})
if __name__ == "__main__":
hello.run(host='0.0.0.0')
Any help getting the 502 error to go away so that I connect to the database is much appreciated. Thank you.
This could be a virtualenv error, check out this link: https://www.pythonanywhere.com/forums/topic/2877/
Very similar question from earlier: ImportError: No module named flask.ext.mysql

web2py function not triggered on user request

Using web2py (Version 2.8.2-stable+timestamp.2013.11.28.13.54.07), on 64-bit Windows, I have the following problem
There is an exe program that is started on user request (first an txt file is created then p is triggered).
p = subprocess.Popen(['woshi_engine.exe', scriptId], shell=True, stdout = subprocess.PIPE, cwd=path_1)
while the exe file is running it is creating a txt file.
The program is stopped on user request by deleting the file the program needs as input.
when exe is started i have other requests user can trigger. it is common that request comes to server (I used microsoft network monitor to check that), but the function is not triggered.
I tried using scheduler but no success. Same problem
I am really stuck here with this problem
Thank you for your help
With a help of web2py google group the solution is.
I used scheduler. Created a scheduler.py file with the following code
def runWoshiEngine(scriptId, path):
import os, sys
import time
import subprocess
p = subprocess.Popen(['woshi_engine.exe', scriptId], shell=True, stdout = subprocess.PIPE, cwd=path)
return dict(status = 1)
from gluon.scheduler import Scheduler
scheduler = Scheduler(db)
In my controller function
task = scheduler.queue_task(runWoshiEngine, [scriptId, path])
you also have to import scheduler (from gluon.scheduler import Scheduler)
then I run the scheduler from command prompt with the following (so if I understood correctly you have two instances of web2py running, one for webserver, one for scheduler)
web2py.py -K woshiweb -D 0 (-D 0 is for verbose logging so it can be removed)

How to pass secure_auth to MySQL login via SQLalchemy

I'm working on the front end of a webapp, and my co-developer is using Pyramid and SQAlchemy. We've just moved from SQLite to MySQL. I installed MySQL 5.6.15 (via Homebrew) on my OS X machine to get the Python MySQLdb install to work (via pip in a virtualenv).
Because in MySQL >= 5.6.5 secure_auth is now ON by default I can only connect to the remote database (pre 5.6.5) with the --skip-secure-auth flag, which works fine in a terminal.
However, in the Python Pyramid code, it only seems possible to add this flag as an argument to create_engine(), but I can't find create_engine() in my co-dev's code, only the connection string below in an initialisation config file. He's not available, this isn't my area of expertise, and we launch next week :(
sqlalchemy.url = mysql+mysqldb://gooddeeds:deeds808letme1now#146.227.24.38/gooddeeds_development?charset=utf8
I've tried appending various "secure auth" strings to the above with no success. Am I looking in the wrong place? Has MySQLdb set secure_auth to ON because I'm running MySQL 5.6.15? If so, how can I change that?
If you are forced to use the old passwords (bah!) when using MySQL 5.6, and using MySQLdb with SQLAlchemy, you'll have to add the --skip-secure-auth to an option file and use URL:
from sqlalchemy.engine.url import URL
..
dialect_options = {
'read_default_file': '/path/to/your/mysql.cnf',
}
engine = create_engine(URL(
'mysql',
username='..', password='..',
host='..', database='..',
query=dialect_options
))
The mysql.cnf would contain:
[client]
skip-secure-auth
For Pyramid, you can do the following. Add a line in your configuration ini-file that holds the connection arguments:
sqlalchemy.url = mysql://scott:tiger#localhost/test
sqlalchemy.connect_args = { 'read_default_file': '/path/to/foo' }
Now you need to change a bit the way the settings are read and used. In the file that launches your Pyramic app, do the following:
def main(global_config, **settings):
try:
settings['sqlalchemy.connect_args'] = eval(settings['sqlalchemy.connect_args'])
except KeyError:
settings['sqlalchemy.connect_args'] = {}
engine = engine_from_config(settings, 'sqlalchemy.')
# rest of code..
The trick is to evaluate the string in the ini file which contains a dictionary with the extra options for the SQLAlchemy dialect.

Integrating Alembic with SQLAlchemy

I'm looking at a way to integrate Alembic with SQLAlchemy. What I need is a way so that Alembic detects any changes I make in models.py automatically and updates it in the MySQL database when I run alembic revision -m "<message_here>" and alembic upgrade head.
Here is what I have at the moment.
This is my application directory structure.
/myapplication
models.py
__init__.py
app.py
/migrations
env.py
script.py.mako
/versions
The models.py contains the following.
from sqlalchemy import Column, Integer, String
from sqlalchemy.ext.declarative import declarative_base
Base = declarative_base()
class User(Base):
""" `User` stores the basic info about a user
"""
__tablename__ = 'user'
id = Column(Integer, primary_key=True)
name = Column(String(255), nullable=False)
phone = Column(String(15), nullable=False)
I have configured my alembic.ini with my database credentials at sqlalchemy.url
I have the following in my env.py
from __future__ import with_statement
from alembic import context
from sqlalchemy import engine_from_config, pool
from logging.config import fileConfig
from myapplication import models
# this is the Alembic Config object, which provides
# access to the values within the .ini file in use.
config = context.config
# Interpret the config file for Python logging.
# This line sets up loggers basically.
fileConfig(config.config_file_name)
# add your model's MetaData object here
# for 'autogenerate' support
# from myapp import mymodel
# target_metadata = mymodel.Base.metadata
target_metadata = models.Base.metadata
# other values from the config, defined by the needs of env.py,
# can be acquired:
# my_important_option = config.get_main_option("my_important_option")
# ... etc.
def run_migrations_offline():
"""Run migrations in 'offline' mode.
This configures the context with just a URL
and not an Engine, though an Engine is acceptable
here as well. By skipping the Engine creation
we don't even need a DBAPI to be available.
Calls to context.execute() here emit the given string to the
script output.
"""
url = config.get_main_option("sqlalchemy.url")
context.configure(url=url)
with context.begin_transaction():
context.run_migrations()
def run_migrations_online():
"""Run migrations in 'online' mode.
In this scenario we need to create an Engine
and associate a connection with the context.
"""
engine = engine_from_config(
config.get_section(config.config_ini_section),
prefix='sqlalchemy.',
poolclass=pool.NullPool)
connection = engine.connect()
context.configure(
connection=connection,
target_metadata=target_metadata
)
try:
with context.begin_transaction():
context.run_migrations()
finally:
connection.close()
if context.is_offline_mode():
run_migrations_offline()
else:
run_migrations_online()
But when the run the migration using
alembic revision -m "initial"
It says
Generating
migrations/versions/2d9d8de1aa80_initial.py...done
But when I open the migrations/versions/9aa5864e4c8_initial.py, this is what I see.
"""initial
Revision ID: 2d9d8de1aa80
Revises: None
Create Date: 2013-02-23 12:21:52.389906
"""
# revision identifiers, used by Alembic.
revision = '2d9d8de1aa80'
down_revision = None
from alembic import op
import sqlalchemy as sa
def upgrade():
pass
def downgrade():
pass
The version file has nothing about the tables I was expecting it to create and later sync with MySQL when I run the command alembic upgrade head. How do I configure Alembic so that when I run the alembic revision command, It picks the schema from models.py and generates a version file? I think I am missing something trivial here. Not sure what it is!
You want to run the revision subcommand with the --autogenerate flag so it inspects the models for changes.
alembic revision --autogenerate -m "some message"
Make sure you're aware of the limitations of the autogenerate option.