Pathlibのsuffix間違ってね?
端的に言えばディレクトリに対してsuffixを呼び出した場合、必ず空文字が帰ってくるわけではない。
ディレクトリ名に「.」が含まれている場合、そこから後ろの文字列が返却される。
自分のsuffixに対する理解
↓公式ドキュメントの一部抜粋
末尾の要素に拡張子があればそれになります:
>>> PurePosixPath('my/library/setup.py').suffix
'.py'
>>> PurePosixPath('my/library.tar.gz').suffix
'.gz'
>>> PurePosixPath('my/library').suffix
''
このサンプルの三番目で、ディレクトリに対してsuffixを呼び出したら、空文字が帰ってきている。
なのでsuffixはファイルの場合は拡張子、ディレクトリの場合は空文字が帰ってくると思った。
たとえ↓のようなディレクトリ名であっても空文字が返却されると思った。
>>> PurePosixPath('my/library.d').suffix
''
実際のsuffixの処理
実際に実行してみる
>>> PurePosixPath('my/library.d').suffix
'.d'
まさかの'.d'。
空文字ではなく'.d'。
実際のpathlib.pyのsuffixのコードを見てみる
~省略~
@property
def suffix(self):
"""The final component's last suffix, if any."""
name = self.name
i = name.rfind('.')
if 0 < i < len(name) - 1:
return name[i:]
else:
return ''
~省略~
見ての通り、単純に'.'を探してあったら切り取ってるだけだった。
ディレクトリかどうかをチェックしていないので、ディレクトリだったとしてもファイルと同様の処理をしている。
そのため、ディレクトリであってもsuffixが空文字以外が返却される可能性がある。
気づいた理由
from pathlib import Path
def print_ext(path: Path):
ext = path.suffix
if ext == '':
print('dir')
elif ext == '.py':
print('py file')
else:
print('other file')
if __name__ == '__main__':
print_ext(Path('my/library.d'))
print_ext(Path('my/library.d/setup.py'))
print_ext(Path('my/library.d/image.jpg'))
実行結果として下のようになると思った。
dir
py file
other file
でも実際は、
other file
py file
other file
解決策
suffixはディレクトリかどうかを確認していないのがそもそもの原因なのでこちらでそれをやってあげる。
from pathlib import Path
def print_ext(path: Path):
ext = path.suffix
if path.is_dir():
print('dir')
elif ext == '.py':
print('py file')
else:
print('other file')
if __name__ == '__main__':
print_ext(Path('my/library.d'))
print_ext(Path('my/library.d/setup.py'))
print_ext(Path('my/library.d/image.jpg'))
このようにis_dir()でディレクトリかどうかをチェックしてそれを条件にすることで解決する。
まとめ
そもそもis_dir()でディレクトリかファイルかのチェックを怠ったのが原因だった。
しかし、ドキュメントも悪い気がする。
ディレクトリに対してsuffixを呼んだ場合のことは文章としては書いていないが、
サンプルの書き方的には、誤解する人がでてきてしまうと思う。
これって仕様なのかな?
~省略~
@property
def suffix(self):
if self.is_dir():
return ''
"""The final component's last suffix, if any."""
name = self.name
i = name.rfind('.')
if 0 < i < len(name) - 1:
return name[i:]
else:
return ''
~省略~
ってやってくれればありがたいんだけどね。