Sql alchemy using connection string with kerberos and impala - python

Actually I use sql alchemy and impala to connect database with creator like :
def conn():
return connect(host=CONNECTION_PARAMETERS["HOST"],
port=CONNECTION_PARAMETERS["PORT"],
database=CONNECTION_PARAMETERS["DATABASE"],
use_ssl=CONNECTION_PARAMETERS["USE_SSL"],
auth_mechanism=CONNECTION_PARAMETERS["AUTH_MECANISM"])
def get_bde_db():
engine = create_engine('impala://', creator=conn,
pool_size=2,
pool_pre_ping=True,
pool_recycle=3600)
user_session_local = sessionmaker(autocommit=False, autoflush=False, bind=engine)
db = user_session_local()
try:
yield db
finally:
db.close()
But I want to change it, stop use the creator parameter and build a connection string in the create_engine. Is it possible to generate a url, and use url parameter ?
I use impala, kerberos, ssl

Related

FASTAPI testing database not creating database

I'm trying to test my FASTAPI app. Seems to me, all settings are correct.
test_users.py
engine = create_engine(
f"postgresql"
f"://{settings.database_username}"
f":{settings.database_password}"
f"#{settings.database_hostname}"
f":{settings.database_port}"
f"/test_{settings.database_name}"
)
TestingSessionLocal = sessionmaker(autocommit=False, autoflush=False, bind=engine)
Base.metadata.create_all(bind=engine)
def override_get_db():
try:
db = TestingSessionLocal()
yield db
finally:
db.close()
app.dependency_overrides[get_db] = override_get_db
client = TestClient(app)
def test_create_user():
response = client.post(
"/users/",
json={"email": "nikita#gmail.com", "password": "password"}
)
new_user = schemas.UserOutput(**response.json())
assert response.status_code == 201
assert new_user.email == "nikita#gmail.com"
When I run pytest, I get this error:
sqlalchemy.exc.OperationalError: (psycopg2.OperationalError) connection to server at "localhost" (::1), port 5432 failed: FATAL: database "test_social_media_api" does not exist
Why is the code not creating the database?
With engine = create_engine("postgresql://...") you define a connection to an existing PostgreSql database.
And with Base.metadata.create_all(bind=engine) you create the tables - according to your models - in the existing database.
So the code that you written does not create a database, it expects that you give it an already existing database.
And that has to do with PostgreSQL itself.
PostgreSQL runs as a server, and a PostgreSQL server can run multiple databases. And each database has to be created explicitly.
Just telling SQLAlchemy the connection string is not enough.
It's possible to create a new database from Python itself by connecting to the PostgreSQL server (see https://www.tutorialspoint.com/python_data_access/python_postgresql_create_database.htm), or alternatively you can create it manually before you run your script. E.g. by running CREATE DATABASE databasename; inside psql (or any other database tool).
However if you want to test using a running database, I would suggest using testcontainers. They will spawn a new PostgreSQL server with an empty database everytime you run the tests.
Notice, that the example from the FastAPI documentation works differently.
They just use
SQLALCHEMY_DATABASE_URL = "sqlite:///./test.db"
engine = create_engine(
SQLALCHEMY_DATABASE_URL, connect_args={"check_same_thread": False}
)
Base.metadata.create_all(bind=engine)
which creates the database.
This works, because SQLite doesn't run as a server. It's just one file that represents the full database, and if the file doesn't exist, the sqlite database adapter will assume that the database is just empty, and create a new file for you. PostgreSQL doesn't work like this though.

multiple database backends per session along with db.execute when using sqlaclhemy

I have this database connection in a fast API app.
I am using multiple binds to the same session, I followed the documentation here:
Query the db:
method1: working
db.query(Model).all()
method2: not working and throwing the following error:
db.execute("SELECT * from ...");
Exception has occurred: UnboundExecutionError
Could not locate a bind configured on SQL expression or this Session.
This is the database connection code...
Can you help me get method2 working?
from sqlalchemy import create_engine
from sqlalchemy.ext.declarative import declarative_base
from sqlalchemy.orm import sessionmaker
from sqlalchemy.ext.automap import automap_base
from sqlalchemy import MetaData
from app.settings import (
db1_DATABASE_URL,
db2_DATABASE_URL
)
engine = create_engine(
db1_DATABASE_URL,
echo=False,
pool_recycle=1800,
pool_timeout=20,
pool_pre_ping=True,
pool_size=50,
max_overflow=100,
)
engine2 = create_engine(db2_DATABASE_URL)
Base = declarative_base()
mroi_Base = automap_base()
mroi_Base.prepare(engine2, reflect=True)
SessionLocal = sessionmaker(autocommit=False, autoflush=False)
SessionLocal.configure(binds={Base: engine, mroi_Base: engine2})
def get_db():
db = None
try:
db = SessionLocal()
yield db
finally:
db.close()
def get_db2():
db2 = None
try:
db2 = SessionLocal()
yield db2
finally:
db2.close()
Remove the below mentioned line as we would be configuring the engine while creating the respective session instances.
SessionLocal.configure(binds={Base: engine, mroi_Base: engine2})
Initialize the session class with respective engine values.
def get_db():
db = None
try:
db = SessionLocal(engine=engine)
yield db
finally:
db.close()
def get_db2():
db2 = None
try:
db2 = SessionLocal(engine=engine2)
yield db2
finally:
db2.close()

How to connect SQLAlchemy to Snowflake database using OAuth2?

I need to connect to Snowflake using SQLAlchemy but the trick is, I need to authenticate using OAuth2. Snowflake documentation only describes connecting using username and password and this cannot be used in the solution I'm building. I can authenticate using Snowflake's python connector but I see no simple path how to glue it with SQLAlchemy. I'd like to know if there is a ready solution before I write a custom interface for this.
Use snowflake.connector.connect to create a PEP-249 Connection to the database - see documentation. Then use param creator of create_engine (docs) - it takes a callable that returns PEP-249 Connection. If you use it then URL param is ignored.
Example code:
def get_connection():
return snowflake.connector.connect(
user="<username>",
host="<hostname>",
account="<account_identifier>",
authenticator="oauth",
token="<oauth_access_token>",
warehouse="test_warehouse",
database="test_db",
schema="test_schema"
)
engine = create_engine("snowflake://not#used/db", creator=get_connection)
I got this working but just adding more params in the connection URL:
from sqlalchemy.engine import create_engine
import urllib.parse
connection_url = f"snowflake://{user}:#{account}/{database}/{schema}?warehouse={warehouse}&authenticator=oauth&token={urllib.parse.quote(access_token)}"
engine = create_engine(connection_url)
with engine.begin() as connection:
print(connection.execute('select count(*) from lineitem').fetchone())
If you don't want to be constructing the URL on your own, you can use snowflake.sqlalchemy.URL like this:
from snowflake.sqlalchemy import URL
connection_url = URL(
user=user,
authenticator="oauth",
token=access_token,
host=host,
account=account,
warehouse=warehouse,
database=database,
schema=schema
)

Is there an elegant way to deal with an oracle connection by python in pytest?

I am in a project which needs to get datum from an oracle database.
The source code reaches the database by cx_Oracle.
Now I wanna find a way to make a fixture for the connection.
Is there an elegant way to make such a fixture?
Or could somebody recommend a pytest-plugin for Oracle connection?
Thanks in advance.
You can use SQLAlchemy for this. Just plug in your connection string into the create_engine string and create a fixture for the connection (and session) like this:
engine = create_engine('your connection string goes here with your login creds')
#pytest.fixture(scope='module')
def connection():
connection = engine.connect()
yield connection
connection.close()
You can read more about the cx_Oracle connection engine from the SQLAlchemy docs here:
Location
Your create_engine might look something like this:
engine = create_engine("oracle+cx_oracle://<username>:<password>#(DESCRIPTION = (LOAD_BALANCE=on) (FAILOVER=ON) (ADDRESS = (PROTOCOL = TCP)(HOST = <host>)(PORT = 1521)) (CONNECT_DATA = (SERVER = DEDICATED) (SERVICE_NAME = devdb)))")
Which was pulled from this post

Postgres sqlalchemy Session creation with schema name

I can able to create postgres sqlalchemy connection to 'public' schema.
url = 'postgresql://scott:tiger#localhost:5432/mydatabase'
engine = create_engine(url)
engine.connect()
session = sessionmaker(bind=engine)
Session = session()
Now try to connect non-public schema say 'myschema'.
engine = create_engine(url, connect_args={"schema" : "myschema"})
engine.connect()
session = sessionmaker(bind=engine)
Session = session()
I got error :
TypeError: connect() got an unexpected keyword argument 'schema'
How can i connect postgres by using able statements.
Thank you.
This is valid connection string for specific schema:
engine = create_engine('postgresql://dbuser:dbpass#localhost:5432/dbname', connect_args={'options': '-csearch_path={}'.format('dbschema')})

Categories