Python Tools for Visual Studioを使って、Raspberry Pi 上のPythonをリモートデバッグする

Raspberry Piでアプリを作成するためにライブラリを探してみたところ、Python製のものが結構ありました。

そのため、慣れているVisual Studio + Python Tools for Visual Studio(以下、PTVS) でPythonを書いてみようと考えました。

 
codeplexには

PTVS supports CPython, IronPython, editing, browsing, Intellisense, mixed Python/C++ debugging, remote linux/MacOS debugging, profiling, IPython, Django, and cloud computing with client libraries for Windows, Linux and MacOS.

と、Linuxへのリモートデバッグに対応しているとの記載がありました。

そこで、Raspberry Pi上のPythonのリモートデバッグができるかを試してみました。

 

環境

Windowsまわり

 

Raspberry Pi まわり
  • Raspberry Pi 2 Model B
  • Raspbian 2015-02-16
  • Python 2.7.3
  • pip 1.1
  • ptvsd 2.1.0

 

流れ

Windowsまわりのセットアップ
PTVSのダウンロード・インストール

以下よりダウンロード・インストールします。
Python Tools for Visual Studio - Downloads

 

Pythonのダウンロード・インストール

2.7系の最新である、Windows x86 MSI installerをダウンロード・インストールします。
Python Releases for Windows | Python.org

 

環境変数の設定

Python2.7.9よりpipがScriptフォルダの下で同梱されるようになったため、以下の2つのパスを環境変数Pathに追加します。

  • C:\Python27
  • C:\Python27\Scripts

Installation — pip 7.0.3 documentation

 

Raspberry Piまわりのセットアップ
pipのインストール

デフォルトではpipが入っていないため、インストールします。
Raspberry Pi Documentation

pi@raspberrypi ~ $ sudo apt-get install python-pip

 

ptvsdのインストール

Raspberry Pi上でリモートデバッグするには、ptvsdが必要になります。

また、stackoverflowの回答より、Raspberry Pi上のptvsd・WindowsのPTVSでバージョンを合わせた方が良さそうでした。
Unable to debug on Raspberry Pi using python tools for visual studio - Stack Overflow

 
そこで、バージョンを指定してpipでインストールします(指定しないと、現時点での最新版2.2.0b1が入ってしまいます)。

pi@raspberrypi ~ $ sudo pip install ptvsd==2.1.0
Downloading/unpacking ptvsd==2.1.0
  Downloading ptvsd-2.1.0.zip (45Kb): 45Kb downloaded
  Running setup.py egg_info for package ptvsd

Installing collected packages: ptvsd
  Running setup.py install for ptvsd

Successfully installed ptvsd
Cleaning up...

 
インストール結果を確認します。なお、Raspbianのpipのバージョンは1.1のため、pip freezeで表示します。

pi@raspberrypi ~ $ pip freeze
...
ptvsd==2.1.0
...

 

PTVSでPythonスクリプトの作成

新しいプロジェクト > インストール済 > テンプレート > 他の言語 > Python より、PythonApplication を選択し、Pythonスクリプトを作成します。

 
サンプルとして、platform.system()の結果を表示するコードを書きます。

# -*- coding: utf-8 -*-

import ptvsd
import platform

ptvsd.enable_attach(secret = 'thinkAmi')

os = platform.system()

print u'ここでアタッチを待ちます'

if os != 'Windows':
    ptvsd.wait_for_attach()

print u'platform.systemの結果は %s です' % os

 
上記のうち、リモートデバッグに関する部分は以下の通りです。

 

ptvsdを使ってリモートデバッグする部分

ptvsdをimportして、アタッチできるようにします。

import ptvsd
ptvsd.enable_attach(secret = 'thinkAmi')

 

リモートデバッグでアタッチされるのを待つ部分

リモートデバッグでアタッチをされるのを待つように指定しないとそのままデバッグが終了してしまうため、忘れないように記述します。

なお、開発端末のWindowsで試した時は発生しないよう、platform.system()の結果がWindows以外の場合(=Raspberry Pi上)のみ、待つようにしています。

if os != 'Windows':
    ptvsd.wait_for_attach()

 

Pythonスクリプト文字コードの変更

Raspberry Pi上で実行するためにPythonスクリプトを転送する必要がありますが、その前にPythonスクリプト文字コードを変更します。

というのも、PTVS 2.1.0で作成したPythonスクリプト文字コードShift_JISとなっているため、そのまま転送すると日本語が以下のように文字化けするためです。

print u'platform.system?????? %s ???' % os

 
そのため、[保存オプションの詳細設定] ダイアログ ボックスを使用して、Pytyonスクリプトの文字コードUTF-8のBOMなしへと変更します。
[保存オプションの詳細設定] ダイアログ ボックス

なお、ダイアログは名前をつけて保存する際に選択するか、以下の方法でメニュー追加します。

 
「保存オプションの詳細設定ダイアログ」では、以下の内容を入力します。

項目
エンコード Unicode (UTF-8 シグネチャなし) - コードページ 65001
行の終わり 現在の設定

改行コード(行の終わり)は現在の設定(おそらく、CR LF) のままでも、Raspberry Pi上で動作しました。

 
なお、メニューに追加した場合、保存オプションの詳細設定ダイアログでOKボタンを押しただけでは保存されないため、忘れないようにCtrl + Sなどで保存します。

 

Pythonスクリプトの転送

Raspberry Pi上にファイルを転送する方法はいくつかあるようですが、今回はGit for Windowsに入っているscp.exeを使います。
Raspberry pi への配置方法 - sample-by-jsakamoto/SignalR-on-RaspberryPi

 

Raspberry Piでの作業

転送先ディレクトリを作成します。

pi@raspberrypi ~ $ mkdir remote_debug
pi@raspberrypi ~ $ ls
python_games  remote_debug

 

Windowsでの作業

コマンドプロンプトなどでscpを使ってPythonスクリプトを転送します。今回は何も考えず、プロジェクト内のファイルをすべて転送します。

# Windows上のファイルを確認
..\RemoteDebugPi>ls
ptvs_raspberrypi.py  PTVSRemoteDebug.pyproj

# scpを使ってファイルを転送
..\PTVSRemoteDebug>scp -r * pi@192.168.0.101:~/remote_debug
#..\PTVSRemoteDebug>scp -r * pi@192.168.0.101:home/pi/remote_debug #=> これも可
pi@192.168.0.101's password:
ptvs_raspberrypi.py                           100%  282     0.2KB/s   00:00
PTVSRemoteDebug.pyproj                        100% 1933     1.9KB/s   00:00

rsyncとSCPについて調べてみた - Pandora Pocket

 

リモートデバッグの実行
Raspberry Pi上でのPythonスクリプトの実行

転送したPythonスクリプトを実行すると、ptvsd.wait_for_attach()が書かれている手前で停止し、TeraTermは以下のような表示となります。

# Pythonスクリプトのディレクトリへと移動
pi@raspberrypi ~ $ cd remote_debug

# Pythonスクリプトを実行
pi@raspberrypi ~/remote_debug $ python ptvs_raspberrypi.py
これからアタッチを待ちます

 

VisualStudioでブレークポイントを設定

今回は変数osの中身を知るため、最終行(このあたり)にブレークポイントを設定します。

なお、ブレークポイントを置かないままプロセスにアタッチすると、Raspberry Pi 上のPythonスクリプトは停止せずに終了してしまいます。

 

Visual Studioでプロセスにアタッチ

ツール > プロセスにアタッチ を選択します。

「プロセスにアタッチ」ダイアログが開きますので、以下のように入力します。なお、修飾子の書式は <secret>@<Raspberry PiのIPアドレス/ホスト名> で、<secret> にはenable_attach()メソッドの引数secretの値が入ります。

項目
トランスポート Python remote debugging
修飾子 thinkAmi@192.168.0.101

 
修飾子の欄でEnterキーを押すと、修飾子の部分がtcp://thinkAmi@192.168.0.101/のように自動補完されるとともに、選択可能なプロセスにRaspberry Pi上のPythonのプロセスが表示されます。

続いて、該当のプロセスを選択して、「アタッチ」ボタンを押します。

すると、ブレークポイントで停止し、VisualStudio上で変数の中身などを確認することができます。

f:id:thinkAmi:20150610185121p:plain  
ブレークポイントを通過すると、TeraTermでは以下の実行結果が表示されます。

pi@raspberrypi ~/remote_debug $ python ptvs_raspberrypi.py
ここでアタッチを待ちます
platform.systemの結果は Linux です

 

その他

enable_attachメソッドにNoneを渡した場合

「プロセスにアタッチ」ダイアログにある「修飾子」欄に、<RaspberryPiのIPアドレス/ホスト名>と入力すれば、自動補完されてアタッチできます。

 

Raspberry Pi の開いているポートについて

RaspberryPi上でptvsdが使用するポートがブロックされている場合、リモートデバッグできません。

そこで、RaspberryPiのデフォルトのブロック状況を見てみたところ、

pi@raspberrypi ~ $ sudo iptables -L
Chain INPUT (policy ACCEPT)
target     prot opt source               destination

Chain FORWARD (policy ACCEPT)
target     prot opt source               destination

Chain OUTPUT (policy ACCEPT)
target     prot opt source               destination

となっており、特に制限はされていないようでした。
Raspberry Pi と iptables - Raspberry Pi を何年か使い続けるブログ

 
また、RaspberryPi上でptvsdを使ったPythonスクリプトを動作させている時に、別のTeraTermを立ち上げてポートの状態を確認してみましたが、

pi@raspberrypi ~ $ netstat -lnt
Active Internet connections (only servers)
Proto Recv-Q Send-Q Local Address           Foreign Address         State
tcp        0      0 0.0.0.0:5678            0.0.0.0:*               LISTEN
tcp        0      0 0.0.0.0:22              0.0.0.0:*               LISTEN

ptvsdのデフォルトポート5678でLISTENしていました。

 

ソースコード

作成したプロジェクトをGitHubに上げておきました。
thinkAmi-sandbox/PTVS-remote_debug-sample

 

参考

PTVSまわり

 

ファイル転送まわり

今回はscpを使いましたが、rsyncについても調べたメモを残しておきます。