単一のPythonデスクトップアプリケーションの開発について

みなさんこんにちは。 この記事では、メモをオフラインで保存するためのオープンソースプログラムであるOutWikerの開発について説明します。 私は自由時間にこのプロジェクトを行います。プログラムの最初のバージョンは2010年にリリースされましたが、OutWikerは引き続き開発を続けています。 歴史的に、私はコードをほとんど独力で実行しました(時には便利な個別のパッチを取得します)が、ユーザーはプログラムを母国語に翻訳することに積極的に関与しており、時にはページのデザインスタイルを送信し、それをアセンブリに含めます。 そして、彼らがどれほど多くの興味深いアイデアを送っているかについて話す価値はありません。







OutWikerとは



Habréでこのプログラムについて書いたことがありますが、内部デバイスの機能と開発プロセスについて話す前に、ユーザーの観点からプログラムが何であるかを言わなければなりません。 プロジェクトに関連するすべてのリンクは、記事の最後に記載されています。 そのため、OutWikerはノートをツリー形式で保存するためのプログラムです。英語を話すインターネットでは、このようなソフトウェアは通常アウトライナーと呼ばれます(したがって、プログラムにはそのような名前が付いています)。 同様の機能を備えたより有名な「同僚」の中で、OutWikerはZim、WikidPad、CherryTree、および他の多く(そしてもちろん、Emacsの組織モード)と呼ばれます。 ユーザーの観点からの論理的な質問は、OutWikerがツリー状のノートブックの他の代表とどのように異なるかです。 現時点では、開発の開始から非常に長い時間が経過した後、このソフトウェアをすべて詳細に展開する準備ができていません。 古代、私は何十ものアウトライナーを試し、5つを長い間使用していましたが、どこでも何かが足りなかったので、WikidPadから1つの機会を、オフラインで動作できるWikidエンジンからもう1つの機会を取りたいと考えました。 したがって、そのような質問に対する答えとして、OutWikerの主な機能を簡単にリストします。













  1. すべてのメモはディスク上のフォルダーとして保存されます。 これには2つの理由があります。信頼性のためです。たとえば、ハードに徐々に死んでいくと、すべてのノートが1つのファイルで他の世界に送られることはありません。 さらに、OutWikerを使用せずにメモを表示および編集できます。 もちろん、このストレージの方法には欠点がありますが、そのようなものは何もありません。
  2. 任意の数のファイルを各メモに添付できます(実際、フォルダーもありますが、この機能は特に宣伝されていません)。 添付ファイル(主に写真)の目的の1つは、メモのテキストでそれらを使用することです。 したがって、添付画像を変更すると、ページのテキストに新しい画像がすぐに表示されます。
  3. OutWikerにはビジュアルエディターはありませんが(いつかは表示されると思いますが、手が届くまで)、いくつかのタイプのページがあります-HTMLページ、wikisages、Markdownページ(対応するプラグインをインストールした後)。 OutWikerはWikiページに焦点を当てています。 ウィキクォートはpmWiki(あまり一般的なサイトエンジンではない)を連想させますが、いくつかの違いはありますが、以下にウィキ表記の機能とその実装について説明します。
  4. 前の段落で既に理解したように、プログラムは現在20を超えるプラグインで動作します。たとえば、ウィキセージのプラグインを使用すると、さまざまなプログラミング言語のコードの色付け、LaTeX形式の数式のサポート、さまざまなカウンターを挿入する機能(たとえば、データ数に応じたグラフ、チャート、チャート、頻繁に入力されるフレーズのテンプレートを追加したり、インターネットなどからダウンロードしてページを作成したりできます。
  5. 各ノートには、任意の数のタグを付けることができます。 タグクラウドがプログラムウィンドウの横に表示されます。
  6. プログラムはクロスプラットフォームであり、WindowsおよびLinux用のアセンブリがあります(Mac OS Xでは、まだ追加しません)。
  7. ソースコードはオープンであり、GPL 3ライセンスの下で配布されています。










インテリアデザインキッチンについての何か



言語と主要なライブラリ



ここで、OutWikerが内部からどのように機能するか、および開発中にどのような問題に対処しなければならなかったかを説明します。







プロジェクト全体はPythonで書かれており、Python 2.7では、Python 3.xへの移行が計画されていますが、近い将来ではありません(理由は少し後で説明します)。 インターフェイスを作成するには、wxPythonライブラリを使用します。 プロジェクトの初期段階では、インターフェイスのライブラリとしてwxPythonとPyQtのどちらかを選択しました。他の同様のライブラリは、WindowsまたはLinuxにとって異質なインターフェイスを作成し、あちこちに存在する可能性があるため拒否されました。 その結果、プログラムのサイズが小さくなったため、wxPythonを停止しました。 私は正確なサイズの数字に名前を付けません。それ以来、プロジェクトは大きく成長しました。 いくつかの不快な瞬間がそれに関連付けられていましたが、wxPythonの選択には満足しています(後で説明します)。







Python言語を選んだのは、すべてがクロスプラットフォームで優れているからです。 最初は、プログラムにプラグインを作成する機能を追加する予定でした。プラグインは通常のPythonスクリプトであるため、異なるオペレーティングシステム用に個別にアセンブルする必要はありません。 一般に、言語を選択することについて後悔はしておらず、その言語のために正確に生じたであろうブレーキはありませんでした。 プログラムには非常に高速に動作しない部分がありますが、主にディスクから大量のファイルを読み取る必要があるという他の理由があります。







クロスプラットフォームに関しては、プログラム内の作業がオペレーティングシステムに依存する場所は多くなく、それらはすべてインターフェイスに接続されています。 おそらく最大の違いは、HTMLページの表示方法です。 WindowsはInternet Explorerエンジンを使用し、LinuxはWebKitを使用します。 OutWikerはwxPython 2.8で動作し、Internet ExplorerおよびWebKitエンジンは、wxPython 3.0とは関係のないハックで使用されていました。現在、これらのエンジンを操作するためのクラスはライブラリに組み込まれています。 確かに、COMオブジェクトへの呼び出しを伴うハックを通じてInternet Explorerを使用し続けます。そのような使用は、エンジンの動作をカスタマイズするためのより多くのオプションを提供するからです。 理論的には、Internet Explorerを介してWindowsで動作し、WebKitを介してLinuxで動作するwx.html2.WebViewクラスにはGetNativeBackend()メソッドがあり、「実際の」エンジンへのポインターを返しますが、何らかの理由でこのメソッドは常に戻りますなし







このプロジェクトはWikidPadプログラムの影響を大きく受けたことを認めなければなりません。 私自身も長い間使用していましたが、Python + wxPythonで書かれていて、時々そのソースを覗いて、そこでどのような瞬間が作られたかを確認しました。 私はそのようなスパイが多くの時間を節約したと言わなければなりません。







ウィキスクリプト



レイアウトのあるページには、HTMLページ、Markdownページ(適切なプラグインを追加する必要があります)、Wikiページの3種類のページがあります。 プログラムにWikiページが必要であるという事実は、プロジェクトの開始以来決定しました。 HTMLとは異なり、ウィキ表記はより簡潔で、新しいコマンドを追加することで簡単に拡張できます。 wikinotationsのもう1つの利点は、埋め込まれたテキストの説明を特定のグラフィックオブジェクトに変換できることです。 たとえば、OutWikerには、LaTeX形式の数式を挿入するコマンド、テキストファイルからのデータまたはページコードに直接挿入されたデータから構築されたグラフを挿入するコマンドがあり、テキストの説明などから図の説明を作成するプラグインがあります。 さらに、Wikiページは最終的にHTMLに変換されてユーザーに表示されるため、たとえばサイトエンジンがHTML入力を期待している場合、サイトの記事を準備するときにも使用できます。 たとえば、今、私はこの記事をウィキ表記の形で書いています。最後に、HTMLタブに切り替えて、完成したHTMLコードを取得します。これは特定のサイトにわずかに適応するだけで済みます。







ウィキメディア概要:













結果:













HTML:













ウィキ表記として、私はpmWikiエンジンに焦点を当てています。あまり一般的ではありませんが、すでに経験があり、その表記の思慮深さが気に入っています。 パーサーの実装のいくつかの時点で、私は元の表記法から離れましたが、一般的にはこれに固執しようとします。 この形式(:command_name :) ...(:command_nameend :)でコマンドを追加するのは非常に簡単です。







なぜ彼らは私が最初にMarkdownを使用しなかったのかと尋ねることがありますが、私の意見では、pmWikiはより論理的であることに加えて、言語が制限されすぎています。 たとえば、Markdownでは、リンクの引数の順序と常に混同されます。[text](http://example.com/)-2種類の括弧、それらの順序は依然として重要です。 使用されているウィキ表記では、リンクは[[text-> example.com ]]の形式で作成されます 。 矢印はリンクの方向を示します。 実際、2番目のリンク形式がありますが、個人的には通常これを使用します。







ところで、OutWikerでは、被害を覚える必要はありません。すべてのデザイン要素は、メニューまたはツールバーを使用して挿入できます。 HTMLおよびMarkdownページの場合、そのようなボタンとメニュー項目も使用できます。







wikiparserを作成するには、非常に便利なpyparsingライブラリが使用されます。 そもそも1つのpyparsing.pyファイルであるという事実により便利です。このファイルはソースに配置でき、プロジェクトで余分な依存関係をプルすることはできません。 このライブラリを使用して、使用されているすべてのウィキ表記トークンが記述され、それらがHTMLに変換されます。 pyparsingに関する詳細なドキュメントがあり、多くの例と小さな本さえあります。 さらに、ライブラリの作成者はサイトのフォーラムに積極的に参加しており、ライブラリの使用を支援する準備ができています。







ローカリゼーション



一部のユーザーは、OutWikerを他の言語に翻訳することに積極的に取り組んでいます。 共同翻訳には、 crowdin.comサービスが使用されます。 これは、ユーザーがフレーズを翻訳して議論するための独自のオプションを提供できる非常に便利なサービスです。













現時点では、プログラムは英語、ロシア語、ウクライナ語、スウェーデン語をサポートしています。 残念ながら、一部の言語のサポートは停止しました。 そのため、たとえば、イタリア語のローカリゼーション(かつてこのローカリゼーションを積極的にサポートしていたイタリア人はどこかに姿を消した)とドイツ語のローカライズ(現在、ドイツ語の一部はドイツ語で、妻はドイツ語の練習として行っている)を終える翻訳者が必要です。誰かが翻訳の2番目の部分をチェックして承認する必要があります。また、プラグインはドイツ語に翻訳されていません)。 誰かが翻訳し始めたいくつかの言語がありますが、それらは頭に浮かびません(ブルガリア語とポルトガル語ブラジル語)。 そしてもちろん、他の翻訳も歓迎します。







ここでは、たとえば、ウクライナ語とスウェーデン語のローカライズのように見えます。



















OutWiker内でローカライズを使用するには、標準のgettextモジュールが使用されます。







ビルド機能



Pythonはインタープリター型プログラミング言語であるため、ユーザーがプログラムを実行するには、理論的にはPythonと必要なすべてのライブラリをインストールする必要があります。 もちろん、普通のユーザーにPython、wxPython、その他の必要なライブラリ、さらには必要なバージョンをインストールするよう強制するのは非人道的です。 ユーザーは、プログラムをダウンロードし、解凍し、インストーラーと「次へ-次へ-次へ」メソッドを使用してインストールし、デスクトップでアイコンを実行する必要があります。 幸いなことに、Pythonで作成されたプログラムの場合、これはすべて比較的簡単に行われます。 Windowsについて話すと、標準ライブラリのないPythonインタープリターは、3 MBよりわずかに大きいdllサイズに収まります。 Pythonスクリプトから実行可能ファイル(Windowsについて説明する場合はexe-shniki)を作成するユーティリティがいくつかあります。 最も有名なものはcx_FreezepyInstallerです。 機能の点では、それらはほぼ同等です(ただし、pyInstallerではPythonスクリプトから単一のexe-shnikを作成できますが、cx_Freezeにはこのオプションはありません)が、* .pycライブラリファイルを保存する場所と設定方法には異なるアプローチがありますビルドオプション。







OutWikerは、ExW Exersを作成するために長い間cx_Freezeを使用しています。 cx_Freeze 5.0がリリースされるまで問題はありませんでした。このバージョンでは、著者はユーティリティの内部を強く書き直しました。 どうやらこれのために、何かがうまくいかなかった。 cx_Freeze 5.0を使用して作成されたOutWikerアセンブリは、起動時にハングし始め、デバッグ結果から判断すると、問題はないと思われる青から外れていました(これはおそらくマルチスレッドと何らかの関係がありました)。 cx_Freeze 5.0.2がリリースされた後、この問題は解消されましたが、OutWikerはプログラムが閉じられたときにメモリからのアンロードを停止しました。 この問題は、プログラムの最後でsys.exit(0)を明示的に呼び出すことで解決できますが、これは私が追加したくない松葉杖です。 さらに、cx_Freeze 5.0.xを使用するときに他のどのような問題が発生する可能性があるかを誰が知っていますか。 実績のあるcx_Freeze 4.xにとどまることは可能ですが、古いライブラリを使用するのは好きではありません。 次に、pyInstallerに切り替えることにしました。 移動は文字通り1日で十分に速くなりました。 新しいアセンブリに問題はありませんでした。 したがって、pyInstallerがアセンブリに使用されるようになりました。 ユーザーの観点から見ると、外見上は何も変わらないはずです。







同じcx_Freeze / pyInstallerを使用してLinux用のバイナリアセンブリを作成することもできます。これにより、結果のアセンブリを異なるLinuxディストリビューションで実行できます。 Windowsでは、Inno Setupを使用して結果のアセンブリからインストーラーが作成され、Linuxでは、同様のアセンブリーからdebパッケージが作成されます(仮想マシンについては、以下で説明します)。







アセンブリのもう1つの機能は、さまざまなアセンブリターゲットの起動方法です。 すべては小さなMakefileから始まりましたが、それは徐々に成長しており、さらに多くの問題がありました。 それらは主にクロスプラットフォームに関連していました-WindowsとLinux用の単一のMakefileを維持するのは困難でした。 当時はうんざりしていたので、代わりのものを探し始めました。できればPythonで書かれたものでした。 Fabricプログラムという形で、代替案がすぐに見つかりました。 これで、以前のすべてのMakefileターゲットは通常のPython関数に書き直され、実際、ビルドシステムは非常に大きくなりました。 たとえば、Fabricタスクリストは次のようになります。









 $ fab -l
利用可能なコマンド:

     apiversion現在のOutWiker APIバージョンを出力します
     apiversions現在のOutWiker APIバージョンを出力します
     build現在のバージョンのアーティファクトを作成します。
    すべてのアセンブリの後にアーティファクトを削除する
     create_treeテスト用のWikiツリーを作成します
     deb debパッケージをアセンブルします
     deb_binaryバイナリdebパッケージを作成
     deb_binary_clearバイナリdebパッケージを削除する
     deb_clear debパッケージを削除する
     deb_install現在のUbuntuリリースのAssemble debパッケージ
     deb_single現在のUbuntuリリースのdebパッケージをアセンブルします
     deb_sources_included PPAでアップロードするファイルを作成します(ソースを含む)
    不安定版をサイトにアップロードする
     doc build documentation
     linux_binary Linux用のAssembleバイナリビルド
     linux_clear Linuxのバイナリビルドを削除する
    ロケールローカライズファイル(outwiker.pot)を更新します
     locale_plugin pluginnameプラグインのローカライズファイルを作成または更新する
     outwiker_changelogサイトのOutWikerの変更ログを生成する
     plugin_changelogサイトのプラグインの変更ログを生成する
     plugin_locale pluginnameプラグインのローカライズファイルを作成または更新します
    プラグインプラグインでアーカイブを作成します(7zが必要です)
     plugins_clearプラグインでアーカイブを削除する(7zが必要)
     plugins_listサイトのプラグインリストを出力します
     prepare_virtual仮想マシンの準備
    ソースからRun OutWikerを実行する
     site_versions現在のOutWikerとプラグインのバージョンをサイト上のバージョンと比較します
     sourcesソースのアーカイブを作成します
     sources_clearソースアーカイブを削除します。
    単体テストのテスト実行
     test_buildビルドユニットテストを実行します
     upload_binary不安定なバージョンをサイトにアップロードする
     upload_pluginプラグインをサイトにアップロードする
     upload_plugins_packすべてのプラグインを含むアーカイブをサイトにアップロードします
     vm_haltビルド用の仮想マシンを停止します
     vm_linux_binary仮想マシンで32ビットおよび64ビットアセンブリを作成する
     vm_prepareビルド用の仮想マシンの準備
     vm_remove_keysリモート仮想マシンのローカルSSHキーを削除します
     vm_runビルド用の仮想マシンの実行
     vm_stopビルド用の仮想マシンを停止します
     vm_update仮想マシンを更新します
     cx_FreezeでBuild OutWiker for Windowsに勝つ
     win_clear Windowsでアセンブリを削除する


ご覧のとおり、多くのコマンドがあり、それらはすべてドキュメントに記載されています 。 これには、WindowsおよびLinuxでのビルド、テストの実行、ビルドのための仮想マシンの操作、ローカリゼーションの更新、サイトへの新しいバージョンの配置などのためのコマンドが含まれます。 ドキュメンテーションから判断すると、Fabricはリモートサーバー(Ansibleの条件付きアナログ)との連携に重点を置いているという事実にもかかわらず、Makefileの代替として本当に気に入っています。







Ubuntu Wars



他のいくつかの不快な瞬間がwxPythonに関連付けられていましたが、幸いなことにすぐに解決されました。 これらの問題はすべて、Ubuntuで発生しました。私は主に開発中にこのことに焦点を当てています(このメインオペレーティングシステムを持っているという事実のため)。 最初の不快な瞬間は、wxPython 2.8から3.0への移行に関連していました(Python 3.xと混同しないでください)。 実際、バージョン2.8から3.0への移行中に下位互換性に問題がありましたが、幸いなことに、これら2つのバージョンを同時にインストールし、Pythonスクリプトからwxversionを使用して目的のバージョンを選択できました。 (wxPython 4.0にはこの機能はありません)。 Pythonはインタープリター言語であり、Ubuntuに常に存在するため、このオペレーティングシステムで実行するバイナリアセンブリを作成する必要はありませんが、debパッケージをインストールするとき、ソースは必要なフォルダーに分散され、 python runoutwiker.pyコマンドを使用して起動されます。 wxPythonとWebKitが機能するために必要なすべてのライブラリは、依存関係としてリストされています。 ただし、Ubuntu 16.04 LTSのリリースでは、2つの問題が発生しました。 1つ目は、このバージョンのUbuntuでwxPython 2.8が削除されたためです。そのため、私は緊急にwxPython 3.0に移行し、別の長寿命バージョンのUbuntu 14.04 LTSのサポートを拒否する必要がありました。 しかし、これだけではありません。Ubuntu16.04(次のバージョンでは修正されました)ではwxPythonが何らかの形で誤ってコンパイルされており、WebKitエンジンはシャーマニズムなしでは機能しません。 幸いなことに、OutWikerの上級ユーザーはここで助けてくれました。LD_PRELOADで問題を回避し、wxPythonに関連する単一のライブラリへのパスを示すことを提案しました。 先ほど言ったように、Ubuntuの将来のバージョンではこの松葉杖の必要性はなくなりましたが、Ubuntu 16.04をサポートするためにはまだ使用する必要があります。







将来、Ubuntuのこのような変更から自分とユーザーを保護するために、最近Linux用のバイナリアセンブリの作成を開始しました。 このようなアセンブリは、32ビットおよび64ビットシステム用に作成されています。 将来的には、これにより、必要なパラメーターを使用してwxPythonを独立してコンパイルでき、Ubuntuリポジトリで利用可能なライブラリに依存しなくなります。 バイナリアセンブリ(およびそれらに基づくdebパッケージ)を作成するために、多数のAnsible、Vagrant、およびVirtualBoxが使用されます。 Vagrantを使用して、2つの仮想マシン(32ビットと64ビット)を起動し、SSH経由でAnsibleを使用してプログラムソースをそこにダウンロードし、バイナリアセンブリとdebパッケージを作成して、作業コンピューター(ホスト)にダウンロードします。 しかし最近、ここでもUbuntu開発者が豚を植えました。 実際のところ、仮想マシンはUbuntu 17.04に基づいており、将来的には仮想マシンをUbuntu 17.10に移行する予定でした。 Ubuntu 16.04 LTSのバージョンを使用してビルドできれば幸いですが、前述したように、wxPythonには問題があります。 しかし、突然、Ubuntu開発者は32ビットシステムのサポートを放棄することにしました。 将来、別の配布キットに切り替えて仮想マシン上で構築する必要がある場合があります。 もちろん、32ビットシステムのサポートを拒否することもできますが、現時点では、そのようなサポートは開発者として私を悩ませることはなく、ユーザーにとって有用です。







使用される他のライブラリ



既に述べたwxPythonおよびpyparsingライブラリに加えて、他のライブラリもプロジェクトで使用されます。 それらを簡単にリストします。









今後の開発計画



githubでのコミットの統計から明らかなように、OutWikerプロジェクトは活発に開発されています。







現在、ソースは約4 MBのファイルを含む約90 MBを占めており、そのうち1772個はpythonスクリプトです。



多くの計画とアイデアがあります(githubの問題の数は現在350を少し下回っています)。 近い将来、彼らの手が確実に実装に届かない場合でも、ユーザーの希望はそこに到達します。 私はほとんどすべて自分でコードを作成しているため、新しい機会は私たちが望むほど早く現れません。 最近、安定したOutWikerバージョンが1年に1回リリースされていますが、毎月不安定版を投稿しています。 実際、私は率直に非稼働バージョンを投稿しないため、それらの不安定性は哲学的な問題です。また、不安定なバージョンは、リリース後に最新リリースの重大でない欠点が修正されるという意味で、安定バージョンよりも「安定」する場合があります。 しかし、不安定なバージョンでは、何かを磨く時間がないか、新しい機能を追加した後に何かに気付かないかもしれません。







現在、作業は2つの方向に進んでいます。プログラムをよりモダンに見せ、各ノートに対して作成されるファイルの数を減らすためです。 インターフェイスについては、既存のツールバーを削除して、Delphiスタイルにしたいです。 しかし、次のバージョン2.2までこのグローバルな変更を残す可能性が高いです。







上記のUbuntuに常に存在する問題に照らして、Linuxでスナップパッケージまたは/およびflatpakパッケージを作成してみたいと思います。







ドキュメントを書く必要があります(私は技術的なことを意味しますが、これまでのところすべてが整いました)。 ドキュメントでは、プログラムの内部構造、アセンブリの機能などについて説明しています。 ほとんどすべてのドキュメントはロシア語で書かれていますが、リリースのために私は一緒になって、少なくともその一部を英語に翻訳したいと思っています。







長期的には、wxPython 4.0にアップグレードする必要があります。wxPython4.0はすぐにリリースステータスを受け取り、Python 3.xに移行することを望んでいます。 最初に両方のバージョンのPythonをサポートするwxPython 4.0に切り替えてから、Python 3に切り替えることは論理的です。







参照資料






All Articles