0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

可搬的なPythonスクリプト実行環境のテンプレートを作成するツールをPythonで改訂 (後編)

Last updated at Posted at 2025-09-13

実践編

前編では、bashスクリプトをpythonで書き換えた経緯と、実装した機能(サブコマンド)について記載した。しかし、このツールの目的は、Pythonで可搬的なスクリプトを作成する際にいつも行う定型作業を自動化するというところにある。基本的には、initサブコマンドを実行すればスクリプトにやりたいことを実装する最低限の準備作業が完了できるようにしている。以下、想定される利用例をいくつか挙げてみる

ファイル置き場

可搬的なスクリプトのセットアップ

新たにmy-new-toolsという名前のツールセットを作成してみます。実行可能なPythonスクリプト(my_new_work_tool.py)と、それに必要なライブラリクラス/関数は別のmy_utils.pyというファイルに実装していくようにしたいとします。また、これらに機能を実装する際にPythonの非標準モジュールのdateutilsを使うことが想定されているとします。

  • 作業ディレクトリ(${workdir})の下のpy_sandboxpy_encaseをダウンロードする
  • それを使って"${workdir}"/my-new-toolsというプロジェクトディレクトリを作成し、その下にファイルを作成
  • README.mdのスケルトンを作成
  • gitのレポジトリとして初期化。ローカルレポジトリとしてだけでなく、remotehost.remotedomainというホストにマスターレポジトリも作成。(ssh経由)

これらは

可搬的スクリプトのセットアップ
% pip3  install --target "${workdir}"/py_sandbox py-encase
% env PYTHONPATH="${workdir}"/py_sandbox: \
    "${workdir}"/py_sandbox/bin/py_encase \
    --manage init --verbose \
    --prefix "${workdir}"/my-new-tools \
    --readme --title  'Tools for my work ....... ' \
    --app-framework \
    --module dateutils \
    --required-module \
    --script-lib 'my_utils.py' \
    --setup-git \
    --git-user-name 'my_git_account' \
    --git-user-email 'my_git_account@my_git_host.domain' \
    --git-set-upstream \
    --git-remote-setup \
    --git-remote-account remote_account \
    --git-remote-host remotehost.remotedomain \
    --git-remote-path '~/git_repositories/' \
    --git-remote-share group \
    --git-protocol ssh \
    my_new_work_tool

長いですが、コマンド2つで準備完了です。

--git-remote-account,--git-remote-host,--git-remote-pathの3つのコマンドラインオプションは、それぞれ環境変数GIT_REMOTE_USER,GIT_REMOTE_HOST,GIT_REMOTE_PATHでも指定可能です。

もしGitHubのCLI(gh)もしくはGitLabのCLI(glab)で、ユーザー情報の登録がセットアップされていれば、 --git-user-name--git-user-emailの2つのオプションの代わりに、--github-userinfoもしくは--gitlab-userinfoというオプションが指定可能です。また、リモートレポジトリとしてGitHubもしくはGitLabを使う場合には、--git-remote-account,--git-remote-host,--git-remote-path,--git-remote-share,--git-protocolの5つのオプションの代わりに、--git-hosting githubもしくは--git-hosting gitlabの1つのオプションで指定可能です。

実行例(py_encase init のターミナル出力)
[.....] mkdir -p : '${workdir}/my-new-tools'
[.....] mkdir -p : '${workdir}/my-new-tools/bin'
[.....] mkdir -p : '${workdir}/my-new-tools/var'
[.....] mkdir -p : '${workdir}/my-new-tools/src'
[.....] mkdir -p : '${workdir}/my-new-tools/var/tmp/python/packages/3.12.11'
[.....] mkdir -p : '${workdir}/my-new-tools/var/log'
[.....] mkdir -p : '${workdir}/my-new-tools/lib/python'
[.....] mkdir -p : '${workdir}/my-new-tools/lib/python/site-packages/3.12.11'
[.....] mkdir -p : '${workdir}/my-new-tools/var/cache/python/packages/3.12.11'
[.....] mkdir -p : '${workdir}/my-new-tools/src/python/packages/3.12.11'
[.....] mkdir -p : '${workdir}/my-new-tools/var/log/pip/25.1.1'
[.....] cp -ai '${workdir}/py_sandbox/py_encase/py_encase.py' '${workdir}/my-new-tools/bin/py_encase.py' 
[.....] make symbolic link : '${workdir}/my-new-tools/bin/mng_encase' --> 'py_encase.py'
[.....] gitignore : '${workdir}/my-new-tools/.gitignore'
[.....] put .gitkeep in '${workdir}/my-new-tools/lib/python/site-packages'
[.....] put .gitkeep in '${workdir}/my-new-tools/var/cache/python/packages'
[.....] put .gitkeep in '${workdir}/my-new-tools/src/python/packages'
[.....] put .gitkeep in '${workdir}/my-new-tools/var/log/pip'
[.....] put .gitkeep in '${workdir}/my-new-tools/var/tmp/python/packages'
[.....] Exec : '/usr/bin/git init ${workdir}/my-new-tools'
[.....] Return code(/usr/bin/git): 0
[.....] STDOUT(/usr/bin/git)     : 'Initialized empty Git repository in ${workdir}/my-new-tools/.git/'
[.....] Exec : '/usr/bin/git config --file ${workdir}/my-new-tools/.git/config user.name my_git_account'
[.....] Return code(/usr/bin/git): 0
[.....] Exec : '/usr/bin/git config --file ${workdir}/my-new-tools/.git/config user.email my_git_account@my_git_host.domain'
[.....] Return code(/usr/bin/git): 0
[.....] Exec : '/usr/bin/ssh remotehost.remotedomain ( test -d ~/git_repositories/my-new-tools.git ||
                                                       git init --bare ~/git_repositories/my-new-tools.git )'
[.....] Return code(/usr/bin/ssh): 0
[.....] STDOUT(/usr/bin/ssh)     : 'Initialized empty Git repository in ...../git_repositories/my-new-tools.git/'
[.....] Exec : '/usr/bin/git --git-dir ${workdir}/my-new-tools/.git 
                             --work-tree ${workdir}/my-new-tools remote add origin
                             ssh://remote_account@remotehost.remotedomain/...../git_repositories/my-new-tools.git'
[.....] Return code(/usr/bin/git): 0
[.....] Exec : '/usr/bin/git --git-dir ${workdir}/my-new-tools/.git 
                             --work-tree ${workdir}/my-new-tools commit 
                             --allow-empty -m Initialize Repository'
[.....] Return code(/usr/bin/git): 0
[.....] STDOUT(/usr/bin/git)     : '[main (root-commit) 2c0d6bb] Initialize Repository'
[.....] Exec : '/usr/bin/git --git-dir ${workdir}/my-new-tools/.git
                             --work-tree ${workdir}/my-new-tools push -u origin main'
[.....] Return code(/usr/bin/git): 0
[.....] STDOUT(/usr/bin/git)     : 'branch 'main' set up to track 'origin/main'.'
[.....] STDERR(/usr/bin/git)     : 'To ssh://remotehost.remotedomain/...../git_repositories/my-new-tools.git
                                    * [new branch]      main -> main'
[.....] Save Readme file : '${workdir}/my-new-tools/README.md'
[.....] Preparing python library file from template : '${workdir}/my-new-tools/lib/python/my_new_work_tool.py'
[.....] make symbolic link : '${workdir}/my-new-tools/bin/my_new_work_tool' --> 'py_encase.py'
[.....] Preparing python library file from template : '${workdir}/my-new-tools/lib/python/my_utils.py'
[.....] Preparing python library file from template : '${workdir}/my-new-tools/lib/python/streamextd.py'
[.....] KV file: '${workdir}/my-new-tools/share/my-new-tools/my_new_work_tool.kv'
[.....] Exec: '.../bin/pip-3.12 --python .../bin/python3.12 install 
                                --cache-dir ${workdir}/my-new-tools/var/cache/python/packages/3.12.11
                                --log ${workdir}/my-new-tools/var/log/pip/25.1.1/pip-log.txt 
                                --target ${workdir}/my-new-tools/lib/python/site-packages/3.12.11
                                --src ${workdir}/my-new-tools/src/python/packages/3.12.11 
                                dateutils pytz tzlocal pkgstruct argparse_extd
                                psutil sshkeyring enc_ds plyer pyobjus kivy'
Collecting dateutils
  Downloading dateutils-0.6.12-py2.py3-none-any.whl.metadata (1.3 kB)
Collecting pytz
  Downloading pytz-2025.2-py2.py3-none-any.whl.metadata (22 kB)
.....

このようにコマンド2つを実行すれば、

  • すぐに${workdir}/my-new-tools/lib/python/my_new_work_tool.py${workdir}/my-new-tools/lib/python/my_utils.pyに実際のコードを実装していくことが可能、
  • ${workdir}/my-new-tools/bin/my_new_work_toolで実行可能、
  • 編集後はすぐにgit add ..., git commit ..., git push ...できる

ので、アイデアをコードに実装することに精神を集中できます。

Pythonモジュールの開発環境のセットアップ

新たにmy_module_devというディレクトリ以下にPythonモジュール(とそれを使う)の開発環境セットアップしてみます。たとえば、これらに機能を実装する際にPythonの非標準モジュールのdateutilsを使うことが想定されているとします。

  • 作業ディレクトリ(${workdir})の下のpy_sandboxpy_encaseをダウンロードする
  • それを使って"${workdir}"/my_module_devというプロジェクトディレクトリを作成し、その配下のサブディレクトリsrc以下にpythonモジュールに必要なファイルのテンプレートを作成
  • gitのレポジトリとして初期化。ローカルレポジトリとしてだけでなく、remotehost.remotedomainというホストにマスターレポジトリも作成。(ssh経由)
pythonモジュールのテンプレート作成
% pip3 install --target "${workdir}"/py_sandbox py-encase

% env PYTHONPATH=$workdir/py_sandbox: \
    "${workdir}"/py_sandbox/bin/py_encase \
    --manage init --verbose \
    --prefix "${workdir}"/my_module_dev \
    --readme \
    --title  'Modules Development ....... ' \

% "${workdir}"/my_module_dev/bin/mng_encase \
    newmodule --verbose \
    --title  'My New Work Utils' \
    --description 'Utility classes for ....' \
    --module-website 'https://github.com/ACOUNT/REPOSITORY' \
    --class-name 'MyNewWorkUtils' \
    --keywords 'utility' \
    --classifiers 'Programming Language :: Python :: 3' \
    --author-name 'my_name' \
    --author-email 'my_email@myhost.domain' \
    --maintainer-name 'my_name' \
    --maintainer-email 'my_email@myhost.domain' \
    --module dateutils \
    --git-user-name 'my_git_account' \
    --git-user-email 'my_git_account@my_git_host.domain' \
    --git-set-upstream \
    --git-remote-setup \
    --git-remote-account remote_account \
    --git-remote-host remotehost.remotedomain \
    --git-remote-path '~/git_repositories' \
    --git-remote-share group \
    --git-protocol ssh \
    my_new_work_utils

前の例と同じく、GitHub CLI(gh)もしはGitLab CLI(glab)のアカウント設定が完了していれば、git-remote関係のオプションは簡略化可能です。

実行例 (mng_encase newmoduleの出力)
[.....] mkdir -p : '${workdir}/my_module_dev'
[.....] mkdir -p : '${workdir}/my_module_dev/bin'
[.....] mkdir -p : '${workdir}/my_module_dev/var'
[.....] mkdir -p : '${workdir}/my_module_dev/src'
[.....] mkdir -p : '${workdir}/my_module_dev/var/tmp/python/packages/3.12.11'
[.....] mkdir -p : '${workdir}/my_module_dev/var/log'
[.....] mkdir -p : '${workdir}/my_module_dev/lib/python'
[.....] mkdir -p : '${workdir}/my_module_dev/lib/python/site-packages/3.12.11'
[.....] mkdir -p : '${workdir}/my_module_dev/var/cache/python/packages/3.12.11'
[.....] mkdir -p : '${workdir}/my_module_dev/src/python/packages/3.12.11'
[.....] mkdir -p : '${workdir}/my_module_dev/var/log/pip/25.1.1'
[.....] cp -ai '${workdir}/py_sandbox/py_encase/py_encase.py' '${workdir}/my_module_dev/bin/py_encase.py' 
[.....] make symbolic link : '${workdir}/my_module_dev/bin/mng_encase' --> 'py_encase.py'
[.....] Save Readme file : '${workdir}/my_module_dev/README.md'
[.....] mkdir -p : '${workdir}/my_module_dev/src/my-new-work-utils'
[.....] mkdir -p : '${workdir}/my_module_dev/src/my-new-work-utils/test'
[.....] mkdir -p : '${workdir}/my_module_dev/src/my-new-work-utils/src'
[.....] mkdir -p : '${workdir}/my_module_dev/src/my-new-work-utils/src/my_new_work_utils'
[.....] put .gitkeep in '${workdir}/my_module_dev/src/my-new-work-utils/test'
[.....] gitignore : '${workdir}/my_module_dev/src/my-new-work-utils/.gitignore'
[.....] Exec : '/usr/bin/git init ${workdir}/my_module_dev/src/my-new-work-utils'
[.....] Return code(/usr/bin/git): 0
[.....] STDOUT(/usr/bin/git)     : 'Initialized empty Git repository in ${workdir}/my_module_dev/src/my-new-work-utils/.git/
'
[.....] Exec : '/usr/bin/git config --file ${workdir}/my_module_dev/src/my-new-work-utils/.git/config user.name my_git_account'
[.....] Return code(/usr/bin/git): 0
[.....] Exec : '/usr/bin/git config --file ${workdir}/my_module_dev/src/my-new-work-utils/.git/config user.email my_git_account@my_git_host.domain'
[.....] Return code(/usr/bin/git): 0
[.....] Exec : '/usr/bin/ssh remotehost.remotedomain ( test -d ~/git_repositories/my-new-work-utils.git ||
                                                       git init --bare ~/git_repositories/my-new-work-utils.git )'
[.....] Return code(/usr/bin/ssh): 0
[.....] STDOUT(/usr/bin/ssh)     : 'Initialized empty Git repository in ...../git_repositories/my-new-work-utils.git/'
[.....] Exec : '/usr/bin/git --git-dir ${workdir}/my_module_dev/src/my-new-work-utils/.git 
                             --work-tree ${workdir}/my_module_dev/src/my-new-work-utils remote add origin
                             ssh://remote_account@remotehost.remotedomain/...../git_repositories/my-new-work-utils.git'
[.....] Return code(/usr/bin/git): 0
[.....] Exec : '/usr/bin/git --git-dir ${workdir}/my_module_dev/src/my-new-work-utils/.git
                             --work-tree ${workdir}/my_module_dev/src/my-new-work-utils commit
                             --allow-empty -m Initialize Repository'
[.....] Return code(/usr/bin/git): 0
[.....] STDOUT(/usr/bin/git)     : '[main (root-commit) e8c8f5e] Initialize Repository'
[.....] Exec : '/usr/bin/git --git-dir ${workdir}/my_module_dev/src/my-new-work-utils/.git 
                             --work-tree ${workdir}/my_module_dev/src/my-new-work-utils push -u origin main'
[.....] Return code(/usr/bin/git): 0
[.....] STDOUT(/usr/bin/git)     : 'branch 'main' set up to track 'origin/main'.'
[.....] STDERR(/usr/bin/git)     : 'To ssh://remotehost.remotedomain/...../git_repositories/my-new-work-utils.git
                                    * [new branch]      main -> main'
[.....] Preparing README from template : '${workdir}/my_module_dev/src/my-new-work-utils/README.md'
[.....] Preparing LICENSE from template : '${workdir}/my_module_dev/src/my-new-work-utils/LICENSE'
[.....] Preparing Makefile from template : '${workdir}/my_module_dev/src/my-new-work-utils/Makefile'
[.....] Preparing pyproject.toml from template : '${workdir}/my_module_dev/src/my-new-work-utils/pyproject.toml'
[.....] Preparing __init__.py from template : '${workdir}/my_module_dev/src/my-new-work-utils/src/my_new_work_utils/__init__.py'
[.....] Preparing my_new_work_utils.py from template : '${workdir}/my_module_dev/src/my-new-work-utils/src/my_new_work_utils/my_new_work_utils.py'

このようにコマンド3つを実行すれば、

  • すぐに${workdir}/my_module_dev/src/my-new-work-utils/以下のモジュールに必要なファイルを編集していくことが可能、
  • ${workdir}/my_module_dev/src/my-new-work-utils/Makefileには、install_localというターゲットが定義されているので、make -C ${workdir}/my_module_dev/src/my-new-work-utils/ install_localを実行すれば、${workdir}/my_module_dev/lib/python/site-packages/以下にインストールされるので、このプロジェクトですぐに利用可能。
  • twineが適切にセットアップされていれば、同じMakefileで容易にPyPIに登録可能
  • 編集後はすぐにgit add ..., git commit ..., git push ...できる

ので、アイデアをコードに実装することに精神を集中できます。

まとめ

1ファイルで可搬的なPythonスクリプトの実行/開発環境を作成するPythonスクリプトpy_encase.pyを作りました。小規模なプロジェクトがコマンド1つで作成可能です。PyPIから容易にダウンロード可能で、セルフアップデート機能も実装してあります。

まだまだバグがありそうなので、注意してご利用ください。(とくにサブコマンドcleandistcleanについては、あらかじめ--dry-runオプションで動作を確認していただければ、と思います。). バグを見つけた場合には教えていただけると助かります。

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?