いろいろ備忘録日記

主に .NET とか Java とか Python絡みのメモを公開しています。

Pythonメモ-97 (python 3.7 + pyinstaller 3.4 + venv で TypeError が出る件)(expected str, bytes or os.PathLike object, not NoneType)

概要

忘れない内にメモメモ。

Python 3.7 + PyInstaller 3.4 + venv の環境で実行ファイルを作成しようとしたら以下のようなエラーが出ました。

8473 INFO: Building PKG (CArchive) PKG-00.pkg
Traceback (most recent call last):
・・割愛・・
  File "C:\Python37\lib\ntpath.py", line 183, in split
    p = os.fspath(p)
TypeError: expected str, bytes or os.PathLike object, not NoneType

環境

$ venv/scripts/activate

(venv) $ python --version
Python 3.7.2

(venv) $ python -m pip show pyinstaller | findstr /L /I version
Version: 3.4

解決方法

調べてみると以下の情報を発見。

github.com

Loran425って人が原因見つけたみたいで、以下の一時コミットを入れてくれています。

github.com

この変更点を、自分の環境の Lib/PyInstaller/depend/bindepend.py に入れるとうまく動くようになります。

この件は別のプルリクで現在もOpenなので、まだ入らないのかな。

github.com

備考

pyinstaller でよく指定しているオプションも、ついでにここにメモ。これもよく忘れるので。

python PyInstaller で よく指定するオプション


過去の記事については、以下のページからご参照下さい。

  • いろいろ備忘録日記まとめ

devlights.github.io

サンプルコードは、以下の場所で公開しています。

  • いろいろ備忘録日記サンプルソース置き場

github.com

github.com

Pythonメモ-96 (async-timeout)(asyncio 互換のタイムアウトクラス)

概要

便利なライブラリがあったので、忘れないうちにメモメモ。

github.com

非同期処理でタイムアウト処理って書くの面倒なんですが、これ使うと楽ですねー。

サンプル

以下、async-timeout モジュールのちょっとしたサンプルです。

"""
async-timeout モジュールについてのサンプルです

基本的な使い方について

REFERENCES:: http://bit.ly/2O0kYNP
"""
import asyncio
import contextlib

from async_timeout import timeout

from trypython.common.commoncls import SampleBase
from trypython.common.commonfunc import pr


# noinspection PyMethodMayBeStatic
class Sample(SampleBase):
    def exec(self):
        asyncio.run(self.async_run())

    async def async_run(self):
        # ---------------------------------------------------------------------------
        # async-timeout モジュール
        # -----------------------------------------
        # asyncio 処理を書く際のタイムアウト処理をスムーズに記述できるようにしてくれるライブラリ
        # timeoutクラスがコンテキストマネージャとして利用できるので async with で利用する
        #
        # オブジェクトには、
        #   - expired
        #   - remaining
        # というプロパティが存在しており、それぞれ
        #   - タイムアウトしたかどうか
        #   - 残り時間
        # を取得できる
        # ---------------------------------------------------------------------------

        # タイムアウト時間内に処理を終えた場合は何も起こらない
        async with timeout(1.5) as tm1:
            await asyncio.sleep(1)
        pr('timeout(1.5) vs sleep(1) expired', tm1.expired)
        pr('timeout(1.5) vs sleep(1) remaining', tm1.remaining)

        # タイムアウトが発生した場合、 asyncio.TimeoutError が raise される
        try:
            async with timeout(1) as tm2:
                await asyncio.sleep(2)
        except asyncio.TimeoutError as e:
            pr('TimeoutError', e)
        else:
            pr('timeout(1) vs sleep(2) expired', tm2.expired)
            pr('timeout(1) vs sleep(2) remaining', tm2.remaining)

        # コンテキストマネージャでタイムアウトしたかわかるので、以下でもいいかも
        with contextlib.suppress(asyncio.TimeoutError):
            async with timeout(1) as tm3:
                await asyncio.sleep(2)

        pr('timeout(1) vs sleep(2) with suppress expired', tm3.expired)
        pr('timeout(1) vs sleep(2) with suppress remaining', tm3.remaining)


def go():
    obj = Sample()
    obj.exec()


if __name__ == '__main__':
    go()

try-python/async_timeout01.py at master · devlights/try-python · GitHub

実行すると以下のような結果となります。

timeout(1.5) vs sleep(1) expired=False
timeout(1.5) vs sleep(1) remaining=0.499564656
TimeoutError=TimeoutError()
timeout(1) vs sleep(2) with suppress expired=True
timeout(1) vs sleep(2) with suppress remaining=0.0

過去の記事については、以下のページからご参照下さい。

  • いろいろ備忘録日記まとめ

devlights.github.io

サンプルコードは、以下の場所で公開しています。

  • いろいろ備忘録日記サンプルソース置き場

github.com

github.com

Pythonメモ-95 (正規表現で絶対最大量指定子を指定する)(re, regex, possessive quantifier, 強欲な量指定子, 標準モジュールではサポートされていない)

概要

昨日の

devlights.hatenablog.com

に引き続き、標準モジュール re でサポートされていない正規表現シリーズ。

忘れない内にメモメモ。

絶対最大量指定子って

名前がすごいイカついですが、概念的にはアトミックグループと同じようなものです。

アトミックグループと同様にバックトラックを抑制するために指定します。

例えば

aaaabbbb

という文字列があって

.*b+

というパターンを指定した場合、最初の .* が全体にマッチします。

ですが、そのままでは、のこりの b+ というパターンにマッチできないので

バックトラックして 最後の文字 b を残りのパターンに譲ります。

なので、 .*aaaabbb にマッチして、b+b にマッチします。

絶対最大量指定子を使う場合、同じパターンを

.*+b+

と指定します。こうすると、上の例と同様に最初の .*+ が全体にマッチしますが

絶対最大量指定子が付いている場合、こいつは自分がマッチしたものを譲りません。

(なので、強欲な量指定子とも呼ばれます。)

譲らないので、残りのパターンがマッチしなくて、結果マッチしないとなります。

regex モジュールを使う

絶対最大量指定子も、標準モジュールの re ではサポートされていないので

regex モジュールを利用します。

(venv) $ python -m pip install regex

サンプル

"""
正規表現のサンプルです。

絶対最大量指定子 (possessive quantifier) について
(絶対最大量指定子は、強欲な量指定子ともいう)

REFERENCES:: http://bit.ly/2NW2TAq
             http://bit.ly/2NXU6Ow
             http://bit.ly/2NXUcFS
             http://bit.ly/2NZDm9v
             http://bit.ly/2NXxyNQ
"""
import re

import regex

from trypython.common.commoncls import SampleBase
from trypython.common.commonfunc import pr


class Sample(SampleBase):

    def exec(self):
        # ------------------------------------------------------------------------
        # 絶対最大量指定子 (possessive quantifier) について
        # -----------------------------------------
        # アトミックグループ (atomic groups) と同じ考え方で導入されたのが
        # 「*+」というメタキャラクタが従う「強欲」という考え方。
        #
        # 「*+」は「*」と似ているが、アトミックグループと同様に、マッチした範囲のステートを
        # 破棄してバックトラックをしないようになる
        #
        # アトミックグループと同様に、この絶対最大量指定子も標準モジュール re ではサポート
        # されていない。 regex モジュールではサポートされている。
        # ------------------------------------------------------------------------

        # 標準 re モジュールは 「*+」をサポートしていない
        s = 'aaaabbbb'
        p = r'.*+b+'
        try:
            re.compile(p)
        except re.error as e:
            pr('re.error', '標準モジュール re では 「*+」はサポートされていない', e)

        # regex モジュールは 「*+」をサポートしている
        #   この場合、パターンとして指定している「.*+b+」の「.*+」が aaaabbbb 全体に
        #   マッチするが、まだパターンとして「b+」が残っているためバックトラックしようと
        #   するが、絶対最大量指定子を指定しているため、バックトラックが発生せずにここで
        #   マッチ失敗と判定される。
        r = regex.compile(p)
        m = r.match(s)
        if not m:
            pr('.*+b+', '絶対最大量指定子を使っているのでマッチしない (正解)')

        # パターンから絶対最大量指定子をなくして、「.*b+」とすると当然マッチする
        p = r'.*b+'
        r = regex.compile(p)
        m = r.match(s)
        if m:
            pr('.*b+', '絶対最大量指定子を使っていないのでマッチする (正解)')


def go():
    obj = Sample()
    obj.exec()


if __name__ == '__main__':
    go()

try-python/re05.py at master · devlights/try-python · GitHub

結果は、以下のようになります。

re.error='標準モジュール re では 「*+」はサポートされていない'(multiple repeat at position 2)
.*+b+='絶対最大量指定子を使っているのでマッチしない (正解)'
.*b+='絶対最大量指定子を使っていないのでマッチする (正解)'

過去の記事については、以下のページからご参照下さい。

  • いろいろ備忘録日記まとめ

devlights.github.io

サンプルコードは、以下の場所で公開しています。

  • いろいろ備忘録日記サンプルソース置き場

github.com

github.com