📝 pytest で alembic のマイグレーションを行う方法

はじめに FastAPI と SQLAlchemy を利用して Web API 開発を行っていた際、SQLAlchemy のマイグレーションツールである alembic を利用していました。 ただ E2E テストを書こうとした際に、pytest 実行中に alembic でデータベースマイグレーションを行う方法が分からず模索していました。結果的にマイグレーションのやり方は分かったものの一応今後も利用するかもしれないため、その内容を記事として残しておくことにしました。 本記事内で利用しているソースコードを含む FastAPI プロジェクトを GitHub リポジトリ上にアップしておいたので、詳細を確認されたい方がいればご参照くださいませ。 alembic でマイグレーションを行う conftest.py にグローバルで利用するマイグレーション用の fixture を定義すれば OK です。 # conftest.py import os import alembic.config import pytest from sqlalchemy import create_engine from sqlalchemy.ext.declarative import declarative_base from sqlalchemy.orm import sessionmaker from sqlalchemy_utils import database_exists, create_database, drop_database # テスト用の初期データを定義した module を import する (必要があれば) # from .seed import users, contents # 指定したパラメータを用いて alembic によるデータベースマイグレーションを行う # 引数のデフォルト設定では全てのマイグレーションを実行するようになっている def migrate(migrations_path, alembic_ini_path='alembic.ini', connection=None, revision="head"): config = alembic.config.Config(alembic_ini_path) config.set_main_option('script_location', migrations_path) if connection is not None: config.attributes['connection'] = connection alembic.command.upgrade(config, revision) # テスト実行用にセットアップされたデータベースのセッション情報を扱う関数 # scope に session を指定することでテスト全体で一回だけ実行されるようにする @pytest.fixture(scope="session", autouse=True) def SessionLocal(): test_sqlalchemy_database_url = os.environ['DATABASE_URL'] engine = create_engine(test_sqlalchemy_database_url) # 既にテスト用データベースが存在していたら破棄する if database_exists(test_sqlalchemy_database_url): drop_database(test_sqlalchemy_database_url) # テスト用データベースを作成する create_database(test_sqlalchemy_database_url) # 環境変数 DATABASE_URL で指定したデータベースに対して、 # マイグレーションを行いテスト実行に必要なテーブルを一括作成する # 第一引数に指定している alembic は `alembic init <環境名>` 実行時に指定した環境名を入力 with engine.begin() as connection: migrate("alembic", 'alembic.ini', connection) Base = declarative_base() Base.metadata.create_all(engine) SessionLocal = sessionmaker(autocommit=False, autoflush=False, bind=engine) # テスト用の各種データを追加する (必要があれば) # db_session = SessionLocal() # for user in users: # db_session.add(user) # db_session.commit() # for content in contents: # db_session.add(content) # db_session.commit() # db_session.close() # テスト用データ追加後のセットアップ済みの状態で # テスト用に利用する SessionLocal を返却する yield SessionLocal # テストが全て終わったら、テスト用データベースを破棄して、 # SQLAlchemy のセッションも切断する drop_database(test_sqlalchemy_database_url) engine.dispose() FastAPI の pytest への適用例 上記を関数を利用する方法は各自のテスト環境によって異なると思いますが、一応私が FastAPI のテストコードを書く際に利用したソースコードを元に参考例を載せておきます。 ...

6月 24, 2021 · 2 分 · Me

📝 Pillow を使って画像に縦書きテキストを埋め込む

はじめに 縦書きテキストを画像に埋め込みたいと頼まれたので、 Python 製の画像処理ライブラリ Pillow を使ってサクッと実装してみました。 一応ソースコードは Gist にもアップ済みです ✍️ https://gist.github.com/nikaera/c1049708ff548b06cab0ae377adc4ac7 動作環境 Python 3.9.5 Pillow 8.2.0 画像に縦書きテキストを埋め込む まずは今回利用する Pillow を予めインストールしておきます。 pip install Pillow その後 main.py を作成して下記を入力します。 テキストを埋め込みたい画像を main.py と同じフォルダに sample.jpeg という名前で配置しておきます。 # Pillow の利用するモジュールのみをインポートする from PIL import Image, ImageDraw, ImageFont # 読み込みたいフォント情報を入力する font_name = "/System/Library/Fonts/ヒラギノ角ゴシック W0.ttc" font_size = 48 font = ImageFont.truetype(font_name, font_size) # テキストを埋め込みたい画像 sample.jpeg を読み込む im = Image.open('sample.jpeg') d = ImageDraw.Draw(im) # 画像に埋め込みたいテキスト情報を入力する # (後述するが、改行コードには未対応) text = "bifdLcFCKXtFJZmPZhzdefjhhYTtuJPAYsR" # 文章を改行するまでの文字数を入力する split_number = 11 # split_number で指定した文字数ごとに分割され配列に格納される # ref: https://qiita.com/yasunori/items/551a7c20ef9b81474e2a splits = [text[i: i+split_number] for i in range(0, len(text), split_number)] # 画像の width を読み込み、画像の右端の座標を取得する # top_right_margin には余白を設定する (描画領域の端が画像の端と被ってしまうため) w, _ = im.size top_right_margin = 13 right_edge = w - top_right_margin # テキストの入力領域に端が赤い四角形を描画する d.rectangle((right_edge, top_right_margin, right_edge - font_size * len(splits), font_size * split_number + top_right_margin), fill=(255, 255, 255), outline=(255, 0, 0)) # 分割した文章を上記四角形内に左にずらしながら縦書き入力する for index, item in enumerate(splits): d.text((right_edge - (font_size / 2) - font_size * index, top_right_margin), item, fill="black", anchor="mt", font=font, direction="ttb") # 縦書きテキストを埋め込んだ画像を test.png として出力する im.save("test.png") 上記ソースコード内で特筆すべき事項として d.text があります。1 まず anchor オプション で文字を横中央に寄せて、縦を上端に寄せるよう設定しています。 ...

5月 22, 2021 · 2 分 · Me