Slide 1

Slide 1 text

PyQt5で自分のためのIDEを 作っちゃおう! Pycon JP 2019 深谷亮祐

Slide 2

Slide 2 text

自己紹介   @fukafukatani 所属: トヨタ自動車株式会社 仕事: 自動運転/物体認識(3D点群/画像) 趣味: 競技プログラミング(AtCoder青)、ボドゲ

Slide 3

Slide 3 text

あらすじ あるIDEで競技プログラミングに参加していたが、いくつかの問題が、、

Slide 4

Slide 4 text

右クリックメニュー縦 に長すぎ問題 項目やたら多い

Slide 5

Slide 5 text

AsMut問題 行末で改行したいだけ なのに補完候補が出ちゃう

Slide 6

Slide 6 text

IDEを自作したモチベーション - どのIDEも「こんな機能がほしい」「この挙動はちょっと気に入らない」がある - やりたいことをやるのにPythonで実現したい - 開発しやすい - ライブラリの充実 Pythonで、自分だけのためのIDEを実現するぞ!

Slide 7

Slide 7 text

ちょっとだけ競プロの話 与えられた問題文の仕様を満たす プログラムを書く 問題文だけでなく入力例と出力例が与え られる 例が複数あるので確認が手間

Slide 8

Slide 8 text

できたもの IDEにブラウザ(PersephoneP)を埋め込み 問題の閲覧をしながら、プログラミングできる 閲覧された問題の入出力例は、バックグラウ ンドでonline-judge-toolsによってダウンロード Testボタンで書いたコードをテストできる!

Slide 9

Slide 9 text

というわけで、本日のコンテンツ - PyQtを使った統合開発環境のアーキテクチャ - QPlainTextEditでメモ帳を作ろう - QPlainTextEditを強化して、プログラミング用エディタにしよう - テキストエディタとデバッガを通信させてIDEに仕上げよう ところどころ、コードが入りますが、 雰囲気を感じていただければ、... 全体はhttps://github.com/fukatani/rujaion

Slide 10

Slide 10 text

というわけで、本日のコンテンツ - PyQtを使った統合開発環境のアーキテクチャ - QPlainTextEditでメモ帳を作ろう - QPlainTextEditを強化して、プログラミング用エディタにしよう - テキストエディタとデバッガを通信させてIDEに仕上げよう

Slide 11

Slide 11 text

Python製IDEってあまり聞かないけどできる の? Integrated Development Environment: 統合開発環境のこと - テキストエディタ(補完、シンタックスハイライト、定義ジャンプ、...) - コンパイル(ビルド)、デバッグ が統合されたソフトウェア 実はPythonはIDEを作れるだけの十分なポテンシャルを有する

Slide 12

Slide 12 text

デバッガ IDEを図にしてみると エディタ 文字キーの入力受付 表示 補完ライブラリ

Slide 13

Slide 13 text

デバッガ 図にしてみると エディタ 補完ライブラリ 既存のライブラリを使用 PDB 既存のライブラリを使用

Slide 14

Slide 14 text

デバッガ 図にしてみると エディタ 補完ライブラリ PyQt+カスタマイズしていく 本発表のメイン

Slide 15

Slide 15 text

PyQtとは PythonのGUIキット、割と人気 IDE向けの機能も充実 - QPlainTextEdit (テキストエディタ) - QCompleter (テキスト補完) - QSyntaxHighlighter (シンタックスハイライト) 既存ライブラリ+PyQtを組み合わせればIDEが作れる!

Slide 16

Slide 16 text

本日のコンテンツ - PyQtを使った統合開発環境のアーキテクチャ - QPlainTextEditでメモ帳を作ろう - QPlainTextEditを強化して、プログラミング用エディタにしよう - テキストエディタとデバッガを通信させてIDEに仕上げよう

Slide 17

Slide 17 text

6行で作るテキストエディタ(QPlainTextEdit) コピペ、アンドゥが可能なエディタが出現 ただし、セーブ/ロードはできない

Slide 18

Slide 18 text

キーバインドの追加 QPlainTextEditを継承し、 keyPressEventをオーバーライド 継承元のキーバインド を有効に キーバインド指定

Slide 19

Slide 19 text

セーブ(名前をつけて保存)の実装 File I/Oでテキスト形式で保存 ウインドウが出現 →選択したファイル名を返す

Slide 20

Slide 20 text

ロードの実装 File I/Oでロードしてテキストをセット ウインドウが出現 →選択したファイル名を返す

Slide 21

Slide 21 text

本日のコンテンツ - PyQtを使った統合開発環境のアーキテクチャ - QPlainTextEditでメモ帳を作ろう - QPlainTextEditを強化して、プログラミング用エディタにしよう - テキストエディタとデバッガを通信させてIDEに仕上げよう ここまででメモ帳レベルのエディタはできた 次はオートインデント、シンタックスハイライトを実装

Slide 22

Slide 22 text

やるべきことは3つ 入力済テキストの取得 テキストの自動挿入 ハイライト (一部箇所のフォントの色変更、波 線、...)

Slide 23

Slide 23 text

やるべきことは3つ オートインデント、補完、スニペット挿入 シンタックスハイライト、対応するカッコ の強調、文法エラー箇所の強調 多くのプログラミング向け機能はこの3つの要素から成立 この辺を実装すると「使えるじゃん!」という感覚になってくる 入力済テキストの取得 テキストの自動挿入 ハイライト (一部箇所のフォントの色変更、波 線、...)

Slide 24

Slide 24 text

オートインデントの動作 def function: “:”で終わる行で改行する と、 (keyPressEventで判定) def function: スペースを四個いれてほしい (正確にはネストを一段下げる)

Slide 25

Slide 25 text

オートインデントの実装 テキスト挿入 カーソル行の テキスト取得 Enterキーのショートカットキーに割当

Slide 26

Slide 26 text

現在行ハイライトの動作 ステップ 1. テキストカーソル位置が”変わる度”に現在行をチェック 2. 現在行の背景色を変える(ハイライト) テキストカーソルが存在する 行の背景色を変更

Slide 27

Slide 27 text

あるイベントが起こる度に カーソルが移動する度に Editorのテキストが変化する度に キーが押される度に マウスホイールが回る度に 現在行の色を変更 文法エラーをチェック 「XXX の度に YYY を行う」という類の実装は、 Qtではシグナルとスロットという概念で扱う

Slide 28

Slide 28 text

現在行ハイライトの実装 (1) カーソルが移動する度に Editorのテキストが変化する度に キーが押される度に 現在行の色を変更 文法エラーをチェック シグナル スロット シグナル 今回はQPlainTextEditのメンバなので実装不要 スロット 今回は自分で実装 接続

Slide 29

Slide 29 text

現在行ハイライトの実装 (2) 背景色の変更: ボリューミーなので、詳しい説明は省略 写経して使ってください 行全体 特定箇所の背景・フォントの 変更、 下線の追加

Slide 30

Slide 30 text

シンタックスハイライトの動作と実装方針 ハイライト自体は現在行のハイライトと同様 テキスト全体を走査し、正規表現にマッチする場所をハイライト ex. - def, class, importなどの予約語との一致 - # の後ろはコメント - 定数(2018, 3.14, None, True) - 文字列リテラル(“Hello World”) QSyntaxHighlighterを使って実装すると楽 シンタックスハイライト実行例

Slide 31

Slide 31 text

本日のコンテンツ - PyQtを使った統合開発環境のアーキテクチャ - QPlainTextEditでメモ帳を作ろう - QPlainTextEditを強化して、プログラミング用エディタにしよう - テキストエディタとデバッガを通信させてIDEに仕上げよう ここまででプログラミング用エディタはできた 補完ライブラリやデバッガと通信して、IDEにしよう

Slide 32

Slide 32 text

補完機能の概要 エディタ 補完ライブラリ import json json.lo load loads ユーザー 候補の選択 選ばれたテキストの挿入 insertPlainText

Slide 33

Slide 33 text

補完ライブラリの叩き方 >>> import jedi >>> source = """import json ... json.lo""" >>> jedi.Script(source, 2, len("json.lo")).completions() [, ] Pythonの補完なら、jediを使うのが楽 (pip install jedi) その行の 何文字目? 何行目? テキスト全体

Slide 34

Slide 34 text

ポップアップ周りの実装概要 (QPlainTextEdit) ポップアップ表示時 のEnter判定 QCompleter(ポップアップ内容の 制御を行うクラス)を継承

Slide 35

Slide 35 text

GUIデバッガを作る前に、、CUIデバッグの流れ 4行目でブレークポイントをしかけて実行 その時点でのaの内容を表示 ユーザー入力文字は水色 “(Pdb)”という文字列が出力されると、入力を受付可能な状態 $ python3 -m pdb myscript.py (Pdb) breakpoint 4 (Pdb) run hello hello >/script.py(4)() (Pdb) print a 40 デバッグしたいプログラム

Slide 36

Slide 36 text

デバッガとの通信 実行中のプログラムから特定の文字列が出力されるのを待つ場合、 対話自動化ライブラリpexpectで実現できる pip install pexpect (Pdb)という文字列が見つかるまでブロックされ、見つかると続行

Slide 37

Slide 37 text

pexpectを使った対話型デバッガ機能の概要 エディタ デバッガ(Pdb) >hello >hello >/script.py(3) (Pdb) run ユーザー 次の指示 Step in / Print a / … (Pdb)という文字列 が現れるまで待機

Slide 38

Slide 38 text

まとめ - PyQtを使ったIDEのアーキテクチャ - QPlainTextEditでメモ帳を作った - プログラミング用エディタ向け機能の実装 - オートインデント(insertPlainText) - 現在行ハイライト - IDE機能の実装 - JediやQCompleterを使った補完 - pexpectを使った対話型デバッガの実装

Slide 39

Slide 39 text

今日話せなかったこと - QThreadを使った重い処理の非同期化 - ブレークポイントの管理 - QtWebEngine - コンソールの実装 https://github.com/fukatani/rujaion PyQt5を使ったRust/C++ IDE (Pythonサポート計画中)

Slide 40

Slide 40 text

ご清聴の皆様、スタッフの皆様、ありがとうございました!  @fukafukatani

Slide 41

Slide 41 text

補足スライド

Slide 42

Slide 42 text

質問1、デバッガの出力はどうやって使うの か? A. パースします。 print aをして、 a = 40という出力が出たなら、” = ”の後ろを取得すればよいです。

Slide 43

Slide 43 text

質問2、PyQt5の動作は遅くないか? A. (実感として)遅くないです。不要な機能がないせいか、有名IDEより速いです。 Visual Studio CodeなどもJavaScriptでできていますし、フロントエンドの速度はあま り問題にならず、補完やデバッグなどのバックエンド側の速度が問題になることが多 いです。 C++の補完をやろうとしたとき、真面目に保管しようとすると標準ライブラリ全部読み 込まないといけないので遅くなりました。(cqueryみたいな解決策はあり)