やりたいこと
例えば, main.py
が他のファイルを呼び出すようなプロジェクトを...
- main.py
- sub1.py
- folder
- sub2.py
↓↓↓ 依存してる関数やクラスなどをちゃーんと...
onefile.py
ぎゅ!!!っとする.
(動機としては, プロジェクト管理しているpythonファイルを楽にgoogle colabで実行できないかな〜と思ったからです.)
解決法
こちら, stickytapeというpythonパッケージを使えばOK.
https://pypi.org/project/stickytape/
stickytape = 粘着テープ
実験
実験したコードは全てGithubに公開してますので, 参考までに.
install
これでstickytapeコマンドが使えるようになる. (コマンド名なげぇ...)
$ pip install stickytape
ファイルを用意
以下のような構成とします.
- main.py
- sub1.py
- folder
- sub2.py
folder/sub2.py
適当にAppleクラスとか作って, 適当にvalueプロパティとか持たせときます.
class Apple:
def __init__(self, value):
self.value = value
sub1.py
適当に平均関数とか作っときます.
def mean(a, b):
return (a+b)/2
main.py
importしてきて適当に計算させて適当に表示します.
from sub1 import mean
from folder.sub2 import Apple
apple1 = Apple(value=100)
apple2 = Apple(value=200)
result = mean(apple1.value, apple2.value)
print(result)
いざ!一つのファイルに!
以下のコマンドを実行します. (もちろんonefile.pyのところは何でもOK)
$ stickytape main.py > onefile.py
結果
以下のようなonefile.py
が生成されます.
#!/usr/bin/env python
import contextlib as __stickytape_contextlib
@__stickytape_contextlib.contextmanager
def __stickytape_temporary_dir():
import tempfile
import shutil
dir_path = tempfile.mkdtemp()
try:
yield dir_path
finally:
shutil.rmtree(dir_path)
with __stickytape_temporary_dir() as __stickytape_working_dir:
def __stickytape_write_module(path, contents):
import os, os.path
def make_package(path):
parts = path.split("/")
partial_path = __stickytape_working_dir
for part in parts:
partial_path = os.path.join(partial_path, part)
if not os.path.exists(partial_path):
os.mkdir(partial_path)
open(os.path.join(partial_path, "__init__.py"), "w").write("\n")
make_package(os.path.dirname(path))
full_path = os.path.join(__stickytape_working_dir, path)
with open(full_path, "w") as module_file:
module_file.write(contents)
import sys as __stickytape_sys
__stickytape_sys.path.insert(0, __stickytape_working_dir)
__stickytape_write_module('sub1.py', 'def mean(a, b):\n return (a+b)/2')
__stickytape_write_module('folder/sub2.py', 'class Apple:\n\n def __init__(self, value):\n self.value = value')
from sub1 import mean
from folder.sub2 import Apple
apple1 = Apple(value=100)
apple2 = Apple(value=200)
result = mean(apple1.value, apple2.value)
print(result)
一瞬「何じゃこりゃ!?」となりましたが, これを実行すると...
150.0
無事正しい計算結果が表示されました.
Google Colabで実験
先ほどのコードをGoogle Colabにコピペして実行しました.
下のように, 無事150.0が表示されました.
(虹色の猫が歩いてるのは気にしないでください.)
スクリプト化
ここからは余談です.
stickytape
というコマンドは長いですし, いちいち生成ファイルのディレクトリを指定するのとか怠いので, 次のようにスクリプト化しておくといいかと思います.
- main.py
- sub1.py
- folder
- sub2.py
- scripts
- tape.sh
- build
- onefile.py
# 初期値
entry="main.py"
output="onefile.py"
# オプション
while getopts e:o: OPT
do
case $OPT in
"e" ) entry=${OPTARG};;
"o" ) output=${OPTARG};;
esac
done
# 実行
stickytape ${entry} > "build/${output}"
以下のコマンドで, main.pyを実行し, buildディレクトリにonefile.pyを生成してくれます.
$ sh scripts/tape.sh
オプションも用意しておきました.
オプション名 | 説明 |
---|---|
-e | エントリポイントのファイル名 |
-o | アウトプットするファイル名 |
$ sh scripts/tape.sh -e <ファイル名> -o <ファイル名>
生成されるディレクトリはbuild
で固定にしているので, 嫌なら勝手に変えてください.
自己紹介
冒頭に書くと邪魔になるので最後にひっそりと自己紹介させてください。
名前 | 綿岡晃輝 |
---|---|
学校 | 神戸大学大学院 |
学部の研究 | 機械学習, 音声処理 |
大学院の研究 | 機械学習, 公平性, 生成モデル, etc |
@Wataoka_Koki |
Twitterフォローしてね!