みなさんこんにちは。先日勃発した、まぃ・3Dスキャンブームの勢いで、良さそうな3Dスキャナをクラウドファンディングでプレッジしたら知財関係でトラブルがあったようで発送が遅れ、悶々とする日々を送っています。今は問題も解決(?)したようで、品物も発送されて、今か今かと首を長くして届くのを待っているところです。この記事が公開される頃には届くと良いなぁと思うのですが、はてさてどうなることやらー?

TEXT_痴山紘史 / Hiroshi Chiyama(日本CGサービス
EDIT_尾形美幸 / Miyuki Ogata(CGWORLD)

前回、駆け足ながらも作成したプログラムを開発・運用するための基礎になる技術をご紹介しました。バージョン管理システムを使って作成したソースコードを管理し、パッケージ管理システムを使ってプログラムを配布、実行環境は仮想環境をつくってパッケージも仮想環境内にインストールというながれをつくることで、環境構築やツールの更新を手軽に行うことができ、さらにはプロジェクトごとに使用するツールのバージョンを切り替えたり、問題のあるバージョンを古いものに戻すという運用を簡単に行えるようになります。

パッケージをつくってみる

自分が作成したプログラムをパッケージ管理システムに乗せるためには、パッケージをつくる必要があります。まずは、簡単な例を使ってパッケージをつくってみます。今回は第38回で作成した binary_search を含む algorithm というパッケージをつくるということでお話を進めていきます。binary_search は algorithm.search.binary_search としてアクセスできるようにしましょう。

パッケージの作成というと敷居が高く感じるかもしれませんが、まったくそんなことはなくて、むしろ簡単すぎて拍子抜けするくらいです。また、Python でパッケージをつくる場合はある程度決まったお作法があるので、それに従うのが良いでしょう。できるだけ標準的なやり方に寄せておくことで、ツールや環境によっては便利な機能を使うことができたり、わざわざ設定する手間を省くことができる場合もあるので、公式がおススメするやり方を採用しておくメリットはとても大きいです。ただ、公式のおススメの方法というのも結構頻繁に見直されて変わっていくので、おススメに沿っていないからといってあまり目くじらを立てる必要もないです。

ではパッケージをつくっていきます。パッケージをつくる際、setup.py をディレクトリのトップに置き、プログラムのソースコードを src に入れるという構成がおススメのようです。それとバージョン管理用の .git、パッケージ開発用の仮想環境 venv などの存在が必要になるでしょう。ただし、venv は各自が用意するものなのでリポジトリには含めないです。

algorithm
 + .git
 + src
 |  +algorithm
 |    +__init__.py
 |    +search.py
 |
 + setup.py
 + venv

venv の中には wheel パッケージをインストールしておきます。これを入れることで .whl 形式のパッケージをつくることができるようになります。

(venv) C:\temp\algorithm>pip install wheel

__init__.py の中身は空のままにしておきます。
search.py の中に binary_search を実装します。

-- search.py --
# -*- coding: utf-8 -*-

def binary_search(list_data, v):
  l = 0
  r = len(list_data)
  while True:
    p = int((l + r) / 2)
    if list_data[p] == v:
      return p
    if v < list_data[p]:
      r = p - 1
    else:
      l = p + 1

if __name__ == '__main__':
  list_data = [pow(i, 2) for i in range(10)]
  print(binary_search(list_data, 9))
----

これらをまとめて .whl ファイルとしてパッケージ化するための setup.py を作成します。setup.py も Python のプログラムなので、Python でできることは何でもできるのですが、単にディレクトリの内容をまとめてパッケージ化するだけであれば setup() を呼ぶだけで良いです。

-- setup.py --
# -*- coding: utf-8 -*-

import setuptools
from setuptools import setup, find_packages

setup(name='algorithm',
      version='1.0',
      description='package sample',
      package_dir={'': 'src'},
      packages=setuptools.find_packages(where='src'),
     )
----

いろいろと引数で指定していますが、name, version, description は名前のまんまですね。package_dir でソースコードのあるディレクトリを指定しています。ソースコードの配置がおススメと異なる場合、ここで指定することができます。

続いて、packages でパッケージに含まれるモジュールを指定します。今回は setuptools.find_packages を使ってリストアップしています。

パッケージ化もしてみます。実行は、仮想環境を有効にした状態で行います。

C:\algorithm>venv\Scripts\activate.bat

(venv) C:\temp\algorithm>python setup.py bdist_wheel
running bdist_wheel
running build
running build_py

(中略)

adding 'algorithm-1.0.dist-info/top_level.txt'
adding 'algorithm-1.0.dist-info/RECORD'
removing build\bdist.win-amd64\wheel

(venv) C:\temp\algorithm>dir dist
 ドライブ C のボリューム ラベルがありません。
 ボリューム シリアル番号は 9A85-C234 です

 C:\temp\algorithm\dist のディレクトリ

2022/06/10  15:53    <DIR>          .
2022/06/10  15:53    <DIR>          ..
2022/06/10  16:26             1,523 algorithm-1.0-py3-none-any.whl
               1 個のファイル               1,523 バイト
               2 個のディレクトリ  1,186,479,312,896 バイトの空き領域

(venv) C:\temp\algorithm>

無事に algorithm-1.0-py3-none-any.whl がつくられました。これはもちろん Python 標準で扱うことのできるパッケージなので、pip コマンドを使用して管理することができます。

※後述するテストを実行する環境をつくるため、開発用の仮想環境にこのパッケージをインストールするのは控えておいてください。

テストを追加する

開発中のコードが正しく動いているか確認するためのテストを追加します。tests フォルダを作成して、その中にテストを格納します。

algogithm
 + .git
 + src
 |  +algorithm
 |    +__init__.py
 |    +search.py
 |
 + tests
 |  +__init__.py
 |  +test_search.py
 |
 + setup.py
 + venv


test_search.py の中は以下のようになっています

-- test_search.py --

# -*- coding: utf-8 -*-
import os
import sys
import pytest

from algorithm import search


class Test_Search:
  def test_binary_search_left(self):
    list_data = [0, 1, 2, 3, 4, 5]
    idx = search.binary_search(list_data, 0)
    assert idx == 0

----

テストの実行

Python でテストを実行するにはいくつかの方法があり、その時々によっておススメの方法が頻繁に変わります。ここでは最近主流の pytest を使用します

まずは pytest をインストールします。

(venv) C:\temp\algorithm>pip install pytest

このままでは tests 以下のテストを実行しても src 以下にあるファイルを見つけられなくてエラーになってしまうので、pip のエディタブルモードで仮想環境にパッケージを登録します。エディタブルモードを使用することで、src 以下のファイルを直接参照してプログラムを実行できるようになります。

(venv) C:\temp\algorithm>pip install -e .

(venv) C:\temp\algorithm>pip list
Package          Version     Editable project location
---------------- ----------- --------------------------
algorithm        1.0         c:\temp\algorithm\src
atomicwrites     1.4.0
attrs            21.4.0

(中略)

virtualenv-clone 0.5.7
wheel            0.37.1

(venv) C:\temp\algorithm>

準備ができたので、テストを実行します。

(venv) C:\temp\algorithm>pytest
================================================= test session starts =================================================
platform win32 -- Python 3.10.4, pytest-7.1.2, pluggy-1.0.0
rootdir: C:\temp\algorithm
collected 1 item

tests\test_search.py .                                                                                           [100%]

================================================== 1 passed in 0.03s ==================================================

(venv) C:\temp\algorithm>

tests 以下にあるテストの自動認識と実行ができました。これで、開発中に好きなときにテストを実行することができます。

まとめ

今回は作成したプログラムのパッケージ化とテストの作成・実行を行いました。ここまでできると、プログラムの開発・運用をシステム化するための手札がかなり揃ってきたことになります。DCC ツールを使用するプロジェクトでも仮想環境を用いることで DCC ツールのインストール先を汚染することなくプロジェクトごとに異なる環境を構築することができますし、開発する際にも Visual Studio Code のような IDE と連携することでテストを実行しながら安全に変更を加えていくことができます。もちろん、開発しているコードはバージョン管理システムを用いることで安心かつ安全に開発を進めることができ、何かトラブルがあった場合でも変更履歴を辿って詳細を確認することができます。

第44回の公開は、2022年7月を予定しております。

痴山紘史

日本CGサービス(JCGS) 代表

大学卒業後、株式会社IMAGICA入社。放送局向けリアルタイムCGシステムの構築・運用に携わる。その後、株式会社リンクス・デジワークスにて映画・ゲームなどの映像制作に携わる。2010年独立、現職。映像制作プロダクション向けのパイプラインの開発と提供を行なっている。新人パパ。娘かわいい。