0
0

More than 3 years have passed since last update.

redirect_stdout で標準出力をキャプチャ (ondryaso/pi-rc522 ライブラリの標準出力を抑制する)

Posted at

「RaspberryPi + ondryaso/pi-rc522 ライブラリで MyFare を操作する」

では、Mifare NFC リーダ/ライタモジュール RFID-RC522 を RaspberryPi / Python3 で使うライブラリとして ondryaso/pi-rc522 を使いました。

大体はうまくいくのですが、時折 E1 とか E2 という文字列が勝手に標準出力されます。python で CUI プログラムを作っていると致命的。

原因

ライブラリのソース中、以下のように特定の条件で無造作に E1 と E2 が print されるようになっています。


.
.
.
        if i != 0:
            if (self.dev_read(0x06) & 0x1B) == 0x00:
                error = False

                if n & irq & 0x01:
                    print("E1")
                    error = True

                if command == self.mode_transrec:
                    n = self.dev_read(0x0A)
                    last_bits = self.dev_read(0x0C) & 0x07
                    if last_bits != 0:
                        back_length = (n - 1) * 8 + last_bits
                    else:
                        back_length = n * 8

                    if n == 0:
                        n = 1

                    if n > self.length:
                        n = self.length

                    for i in range(n):
                        back_data.append(self.dev_read(0x09))
            else:
                print("E2")
                error = True
.
.
.

仕方ないですねえ

ライブラリに手を加える → やめました

上記の print("E1") だとか print("E2") をコメントアウトしたり、print("E1", file=sys.stderr) のようにすれば良い。
そのようにライブラリを書き換えようかな? と思って、インストールしている場所をしらべてみたら・・・


/usr/local/lib/python3.7/dist-packages/pi_rc522-2.2.1-py3.7.egg

にありました。egg形式・・・ ALZip アーカイブ形式かと思いきや、python の setuptools に使われる単なるZipファイルだそうです。
めんどくさそうなので別のやり方で対処することにしました。

redirect_stdout を呼び出し側で使う

ライブラリ呼び出し側の Python プログラム中で対処する方法です。

redirect_stdout を使うと、標準出力を Python プログラム上でリダイレクトすることができます。
Python 3.5 以降で導入されたらしいです。

以下は、https://github.com/ondryaso/pi-rc522/blob/master/README.md から UID を表示する部分を抜粋したものです。


from pirc522 import RFID
rdr = RFID()

f = io.StringIO()

while True:
  rdr.wait_for_tag()
  (error, tag_type) = rdr.request()
  if not error:
    print("Tag detected")
    (error, uid) = rdr.anticoll()
    if not error:
       print("UID: " + str(uid))

# Calls GPIO cleanup
rdr.cleanup()

上記を redirect_stdoutを導入して書き直すと以下のようになります。


import io
import os
from contextlib import redirect_stdout

from pirc522 import RFID
rdr = RFID()

f = io.StringIO()

while True:
  rdr.wait_for_tag()
  with redirect_stdout(f):
      (error, tag_type) = rdr.request()
  # print(f.getvalue())  # if need print "E1" or "E2"
  if not error:
    print("Tag detected")
    with redirect_stdout(f):
      (error, uid) = rdr.anticoll()
    # print(f.getvalue())  # if need print "E1" or "E2"
    if not error:
       print("UID: " + str(uid))

# Calls GPIO cleanup
rdr.cleanup()

上記では E1,E2のエラーをキャプチャーするために、


f = io.StringIO()

としていますが、キャプチャーする必要が無く捨てるだならば


f = open(os.devnull,'w')

とするのでもOKです。

参考
「Pythonで外部ライブラリが標準出力に吐くメッセージを抑制する」
https://qiita.com/zophos/items/2d3aee100eb4f17bd147

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