事の起こり
本事象を確認したPipenvのバージョンは以下です。
$ pipenv --version
pipenv, version 2021.11.9
- その他環境情報
- macOS Monterey バージョン 12.0.1
- Python 3.8.11, 3.9.6, 3.10.0b4
Homebrewでアップデートを実行したところ、Pipenvが最新版にアップデートされました。その後、シェルの起動時に以下のエラーメッセージが出力される様になりました。。。
Usage: pipenv [OPTIONS] COMMAND [ARGS]...
Try 'pipenv -h' for help.
Error: No such option: --completion Did you mean --python?
yuhkiyano:~ $ pipenv
Pipenv実行時にTAB補完が出来る様にするために、--completion
オプションが用意されていますが、どうやら使えない様なのです。よもや--python
オプションに統合されてしまったのか。。。試しに.bashrcの中の設定を以下の様に変更してみました。
- eval "$(pipenv --completion)"
+ eval "$(pipenv --python)"
案の上ですが、以下のメッセージが表示されました。。。
$ . .bashrc
Error: Option '--python' requires an argument.
公式ドキュメントを参照したところオプションが変更されていた。。。
公式ドキュメントに救いを求めたところ、何とオプションが変更されていました!!
☤ Shell Completion
To enable completion in fish, add this to your configuration:
eval (env _PIPENV_COMPLETE=fish_source pipenv)
Alternatively, with zsh, add this to your configuration:
eval "$(_PIPENV_COMPLETE=zsh_source pipenv)"
Alternatively, with bash, add this to your configuration:
eval "$(_PIPENV_COMPLETE=bash_source pipenv)"
Magic shell completions are now enabled!
公式ドキュメント通りにしてはみたものの今度は別の問題が発生
公式ドキュメント通りに.bashrc
に設定を追記しました。しかし、シェル起動時に以下のエラーが出力され、問題は解決しませんでした。MacにはそもそもBashのバージョン3がデフォルトでインストールされています。しかし、Pipenvの最新版からcompletionがBashのバージョン3は非対応となり、バージョン4.x以降が必要となりました。よって、筆者のMacにはバージョン5がインストールされています。通常なら動作するはずなのですが。。。
Traceback (most recent call last):
File "/usr/local/Cellar/pipenv/2021.11.9/libexec/bin/pipenv", line 8, in <module>
sys.exit(cli())
File "/usr/local/Cellar/pipenv/2021.11.9/libexec/lib/python3.10/site-packages/pipenv/vendor/click/core.py", line 1137, in __call__
return self.main(*args, **kwargs)
File "/usr/local/Cellar/pipenv/2021.11.9/libexec/lib/python3.10/site-packages/pipenv/vendor/click/core.py", line 1057, in main
self._main_shell_completion(extra, prog_name, complete_var)
File "/usr/local/Cellar/pipenv/2021.11.9/libexec/lib/python3.10/site-packages/pipenv/vendor/click/core.py", line 1132, in _main_shell_completion
rv = shell_complete(self, ctx_args, prog_name, complete_var, instruction)
File "/usr/local/Cellar/pipenv/2021.11.9/libexec/lib/python3.10/site-packages/pipenv/vendor/click/shell_completion.py", line 45, in shell_complete
echo(comp.source())
File "/usr/local/Cellar/pipenv/2021.11.9/libexec/lib/python3.10/site-packages/pipenv/vendor/click/shell_completion.py", line 324, in source
self._check_version()
File "/usr/local/Cellar/pipenv/2021.11.9/libexec/lib/python3.10/site-packages/pipenv/vendor/click/shell_completion.py", line 319, in _check_version
raise RuntimeError(
RuntimeError: Couldn't detect Bash version, shell completion is not supported.
結論: completionのソースを修正する必要が有りました
エラーの原因となっているソースを開いて見てみると、バージョンの数値を取ってくる処理の部分で転けていることが分かりました。原因となっている箇所(shell_completion.pyの319行目近辺)を以下に示します。
class BashComplete(ShellComplete):
"""Shell completion for Bash."""
name = "bash"
source_template = _SOURCE_BASH
def _check_version(self) -> None:
import subprocess
output = subprocess.run(["bash", "--version"], stdout=subprocess.PIPE)
match = re.search(r"version (\d)\.(\d)\.\d", output.stdout.decode())
if match is not None:
major, minor = match.groups()
if major < "4" or major == "4" and minor < "4":
raise RuntimeError(
_(
"Shell completion is not supported for Bash"
" versions older than 4.4."
)
)
else:
raise RuntimeError(
_("Couldn't detect Bash version, shell completion is not supported.")
)
標準出力に出力されているエラーメッセージが文字列としてコーディングされている箇所が該当箇所です。よく見ると、bash --version
コマンドを実行し、実行結果を文字列として取得しています。ここで、Bashバージョン3とBashバージョン5でのbash --version
コマンドの実行結果を示します。
どうやらバージョン4での実行結果はバージョン3と同じ様なフォーマットの出力になる様です。
$ /bin/bash --version
GNU bash, version 3.2.57(1)-release (x86_64-apple-darwin21)
Copyright (C) 2007 Free Software Foundation, Inc.
$ bash --version
GNU bash, バージョン 5.1.8(1)-release (x86_64-apple-darwin20.3.0)
Copyright (C) 2020 Free Software Foundation, Inc.
ライセンス GPLv3+: GNU GPL バージョン 3 またはそれ以降 <http://gnu.org/licenses/gpl.html>
This is free software; you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law.
上記のshell_completion.py
のソース抜粋の11行目で正規表現でマッチングを実行していますが、バージョン5での実行結果にversion
という文言が出て来ておらず、日本語でバージョン
という表記になっています。故に実行結果がNone
となり、エラー終了していたことが判明しました。
正規表現の修正
正規表現の修正が必要になりました。最初は、version
を取り去るだけで済ませようかとも思いましたが、それで誤った部分がマッチングしてしまうことは避けなければなりません。少し考えて以下の様に修正しました。
output = subprocess.run(["bash", "--version"], stdout=subprocess.PIPE)
- match = re.search(r"version (\d)\.(\d)\.\d", output.stdout.decode())
+ match = re.search(r"(\d)\.(\d)\.\d+\(1\)-release", output.stdout.decode())
バージョン番号(1)-releaseと言う部分は、新旧のバージョン間で変わらなかったので、この部分でマッチングを実行することにしました。
修正結果
Pipenvを正常に実行できました。TAB補完も生きています。
$ pipenv
Usage: pipenv [OPTIONS] COMMAND [ARGS]...
Options:
--where Output project home information.
--venv Output virtualenv information.
--py Output Python interpreter information.
--envs Output Environment Variable options.
--rm Remove the virtualenv.
--bare Minimal output.
--man Display manpage.
--support Output diagnostic information for use in
GitHub issues.
--site-packages / --no-site-packages
Enable site-packages for the virtualenv.
[env var: PIPENV_SITE_PACKAGES]
--python TEXT Specify which version of Python virtualenv
should use.
--three / --two Use Python 3/2 when creating virtualenv.
--clear Clears caches (pipenv, pip). [env var:
PIPENV_CLEAR]
-v, --verbose Verbose mode.
--pypi-mirror TEXT Specify a PyPI mirror.
--version Show the version and exit.
-h, --help Show this message and exit.
Usage Examples:
Create a new project using Python 3.7, specifically:
$ pipenv --python 3.7
Remove project virtualenv (inferred from current directory):
$ pipenv --rm
Install all dependencies for a project (including dev):
$ pipenv install --dev
Create a lockfile containing pre-releases:
$ pipenv lock --pre
Show a graph of your installed dependencies:
$ pipenv graph
Check your installed dependencies for security vulnerabilities:
$ pipenv check
Install a local setup.py into your virtual environment/Pipfile:
$ pipenv install -e .
Use a lower-level pip command:
$ pipenv run pip freeze
Commands:
check Checks for PyUp Safety security vulnerabilities and against PEP
508 markers provided in Pipfile.
clean Uninstalls all packages not specified in Pipfile.lock.
graph Displays currently-installed dependency graph information.
install Installs provided packages and adds them to Pipfile, or (if no
packages are given), installs all packages from Pipfile.
lock Generates Pipfile.lock.
open View a given module in your editor.
run Spawns a command installed into the virtualenv.
scripts Lists scripts in current environment config.
shell Spawns a shell within the virtualenv.
sync Installs all packages specified in Pipfile.lock.
uninstall Uninstalls a provided package and removes it from Pipfile.
update Runs lock, then sync.
まとめ
アップデート直後にシェルを再起動したら、Pipenvのcompletionに関するエラーメッセージが表示されることに端を発したトラブルの解決は、最初は簡単に直るだろうと高をくくっていたのですが、予想外に時間が掛かりました。本記事では割愛していますが、subprocessでの実行をechoコマンドに変更してみたり、環境変数を直接Python取る方式での修正を試みたりしたものの、思う様な成果が得られず、最終的に辿り着いた修正が本記事での修正です。折角なので、本家GitHubにIssueを発行して、序でにソースの修正もCommit & Pushしようと思っています。
2021/11/14追記: 本家は修正されていました。
記事投稿後、本家のソースを調べてみたところ、修正されていました。どうやらHomebrewでインストールされるバージョン固有の問題の可能性が出て来ました。しばし静観することとします。