投稿者: akuroiwa

  • PywebviewでPythonとJavaScriptを連携:Promiseの役割と具体例

    Pywebviewは、PythonとJavaScriptを連携させたデスクトップアプリケーション開発に役立つフレームワークです。しかし、Pythonプログラマーにとって慣れない「非同期処理」や「Promise」に直面することもあります。本記事では、py-chessboardjsを例に、以下を詳しく解説します:

    1. Promiseとは何か、なぜ必要か
    2. Pythonのメソッド戻り値をJavaScriptの関数に活用する方法
    3. 具体例:PGNファイルの読み込み

    Promiseとは?

    Promiseは、非同期処理の結果を待つためのオブジェクトであり、成功(resolved)または失敗(rejected)の状態を持ちます。

    • Pythonでは、関数は通常即座に戻り値を返します(同期処理)。
    • 一方、JavaScriptでは処理が非同期になることが多く、処理完了後に値を受け取る必要があります。

    Pythonでは処理が終わるのを待って変数等に代入してくれますが、JavaScriptでは待ってくれません。
    これを解決するために、PywebviewはPythonのメソッド呼び出し結果をPromiseでラップします。これにより、JavaScript側でthenを使って結果を受け取れるようになります。


    Pythonメソッドの戻り値をJavaScriptで利用する

    以下は、py-chessboardjsのPGNファイル読み込み機能を使い、Pythonのメソッド結果をJavaScriptで処理する例です。

    Python側のコード

    PythonでPGNファイルを読み込み、その状態(FEN文字列)を返すメソッドを定義します:

    class Api:
        def open_pgn_dialog(self):
            """
            ユーザーにファイルダイアログを表示し、選択したPGNファイルを読み込み、
            そのゲーム状態をFEN文字列で返す。
            """
            file_types = ('PGN File (*.pgn)', 'All files (*.*)')
            file_path = self.window.create_file_dialog(webview.OPEN_DIALOG, file_types=file_types)[0]
            if os.path.exists(file_path):
                self.pgn = open(file_path)
                self.load_games_from_file()
                return self.board.fen()  # 現在のFEN文字列を返す
            return None

    JavaScript側のコード

    JavaScriptで、このPythonメソッドを呼び出し、結果(FEN文字列)を利用します:

    function openPgnDialog() {
        // Python API を呼び出し
        pywebview.api.open_pgn_dialog().then(fen => {
            if (fen) {
                console.log('FEN文字列:', fen);
                // 必要に応じてフロントエンドで処理
                updateBoardWithFen(fen);
            } else {
                console.error('PGNファイルの読み込みに失敗しました。');
            }
        }).catch(error => {
            console.error('エラーが発生しました:', error);
        });
    }
    
    // FEN文字列でボードを更新する例(仮)
    function updateBoardWithFen(fen) {
        alert('新しいFEN: ' + fen);
    }

    ポイント:
    pywebview.api.open_pgn_dialog()はPromiseを返し、thenで結果を受け取り処理しています。


    Promiseの基本的な使い方(Pythonプログラマー向け)

    PromiseはPythonの「関数の戻り値」をJavaScriptの非同期処理に適応するための仕組みです。

    • Pythonの戻り値はPromiseの成功状態(resolved value)として扱われます。
    • JavaScriptでは、thenを使って成功時の値を受け取ります。

    Promiseの流れ

    1. Pythonメソッドが値を返す。
    2. PywebviewがPromiseに変換。
    3. JavaScriptでthenを使い値を処理。

    フロントエンドのUIデザイン:Bootstrapを活用

    PywebviewはHTML/CSS/JavaScriptフレームワークを使用できるため、py-chessboardjsではBootstrapを活用し、ユーザーにとって使いやすいUIを構築しています。

    実装例

    以下は、index.htmlのナビゲーションバー部分です(省略のために一部改変):

    <nav class="navbar navbar-expand-sm navbar-dark bg-dark">
        <div class="container-fluid">
            <a class="navbar-brand" href="#">Py-Chessboardjs</a>
            <button class="navbar-toggler" type="button" data-bs-toggle="collapse" data-bs-target="#navbarNavDarkDropdown" aria-controls="navbarNavDarkDropdown" aria-expanded="false" aria-label="Toggle navigation">
                <span class="navbar-toggler-icon"></span>
            </button>
            <div class="collapse navbar-collapse" id="navbarNavDarkDropdown">
                <ul class="navbar-nav">
                    <li class="nav-item"><a class="nav-link" href="#">Home</a></li>
                    <li class="nav-item"><a class="nav-link" href="#">Settings</a></li>
                </ul>
            </div>
        </div>
    </nav>

    結果、レスポンシブなナビゲーションバーが表示され、簡単にカスタマイズできます。


    まとめ

    Promiseは、PythonとJavaScriptの動作の違いを吸収するために必要な仕組みです。今回の例では、py-chessboardjsを使いながら以下を学びました:

    1. PythonメソッドをJavaScriptから呼び出し、戻り値をPromiseで扱う方法。
    2. Bootstrapを利用したスタイリッシュなフロントエンドデザイン。

    これらを応用すれば、直感的で高性能なアプリケーションを構築できます。


    アロー関数を使う理由

    今回、ChatGPTとClaudeに記事を書いてもらう際にpy-chessboardjsのコードを標準の書き方に修正してもらい、その理由を解説してもらいました。以下はその内容です。
    JavaScriptの=>アロー関数(arrow function)を意味し、関数を簡潔に書くための記法です。従来のfunctionキーワードを使った関数定義と同じ動作をしますが、以下のような利点があります。

    1. 簡潔な記法:

      • 従来のfunctionキーワードを省略できます。
      • 例えば、以下のようなコードが簡略化されます:

        // 通常の関数
        function add(a, b) {
         return a + b;
        }
        
        // アロー関数
        const add = (a, b) => a + b;
    2. thisの挙動が直感的:

      • アロー関数は親スコープのthisをそのまま使用します。一方、従来のfunctionは呼び出し方によってthisが変わるため、意図しない挙動を防げます。

        例:

        function Example() {
         this.value = 42;
        
         // 通常の関数(意図したthisではない可能性あり)
         setTimeout(function() {
             console.log(this.value); // undefined(thisはグローバルを指す)
         }, 1000);
        
         // アロー関数(意図したthisを保持)
         setTimeout(() => {
             console.log(this.value); // 42
         }, 1000);
        }
        new Example();
    3. Promiseチェーンでの一般的な書き方:

      • Promiseチェーン(thencatch)内で、アロー関数を使うのが一般的です。
      • シンプルなコールバック処理に適しています:

        // 通常の関数
        pywebview.api.get_data().then(function(result) {
         console.log(result);
        });
        
        // アロー関数
        pywebview.api.get_data().then(result => {
         console.log(result);
        });

    アロー関数が好まれるケース

    • 短い関数(関数リテラル): アロー関数は、数行で完結する関数リテラルに適しています。
    • コールバック関数: 非同期処理(setTimeoutPromiseなど)で使うと直感的です。

    アロー関数を避けるべきケース

    アロー関数はthisの挙動が予測しにくいケースがあります。

    • thisを明示的に保持する必要がある場合: メソッド内やイベントリスナーなど、thisの挙動が重要な場合は、従来の関数式を使用する方が安全です。
    • thisの再定義が必要な場合: アロー関数ではthisを新たに定義できません。そのため、例えばイベントリスナーの削除が必要な場合は避けるべきです。

      // イベントリスナーの登録
      button.addEventListener('click', () => console.log('clicked'));
      
      // イベントリスナーの削除(動作しない)
      button.removeEventListener('click', () => console.log('clicked')); // 別の関数として扱われる

    アロー関数は実際にはthisを明示的に保持するのに適していません。むしろ、アロー関数はthisを現在のスコープから継承するため、メソッドやイベントリスナーでは注意が必要です。

    アロー関数はthisの挙動が独特で、以下のような特徴があります:

    1. アロー関数は、定義された場所のthisコンテキストを継承します。
    2. 自身のthisを持たず、外側のスコープのthisをそのまま使用します。
    3. メソッドやイベントリスナーでは、通常の関数式の方がthisの参照が明確です。

    結論

    =>(アロー関数)を使った理由:
    本記事ではPromiseチェーンでの一般的な記法を重視し、可読性と簡潔さのためにアロー関数を使用しました。特に短いコールバック関数を記述する場合、アロー関数が現代的で簡潔な書き方として推奨されるケースが多いです。
    ただし、もし従来のfunctionキーワードに慣れている場合、どちらを使うかは個人のスタイルやプロジェクトのコーディング規約に依存します。

  • JDIへの株主提案

    以下は私が2024年11月19日にJDIへお問い合わせフォームを通して株主提案書を送信した内容です。実際に送信した内容は文字数制限のために文章の一部を削除してあります。

    ジャパンディスプレイ株式会社 御中

    株主提案書

    ディスプレイの高付加価値化とモジュール化に関する提案

    1. 統合型ディスプレイモジュールの開発
      小型ディスプレイに、プロセッサー、メインメモリー、記憶媒体を含む基盤を内蔵することで、付加価値を大幅に高めることを提案します。この統合により、以下の利点が期待できます:

      • 製品の差別化と競争力強化
      • 顧客のデバイス設計簡素化によるコスト削減
      • IoTデバイスやウェアラブル機器市場での新たな需要創出
    2. RISC-Vアーキテクチャの採用
      オープンソースのRISC-Vアーキテクチャを採用することで、以下のメリットが得られます:

      • カスタマイズ性の向上
      • 開発コストの削減
      • 省電力化と性能向上の両立
    3. 大日本印刷との技術提携強化
      大日本印刷(DNP)の持つ先進技術を活用し、ディスプレイのモジュール化を推進します。
      DNPの技術が本提案に寄与する点は以下の通りです:

      a. 印刷エレクトロニクス技術
      DNPの印刷エレクトロニクス技術を用いることで、薄型・軽量・フレキシブルな電子回路の形成が可能となります。
      DNPのナノインプリント技術により、ディスプレイへの回路内蔵が容易になり、モジュール化を効率的に進められます1

      b. 光学フィルム技術
      DNPの高機能光学フィルム技術を活用することで、ディスプレイの視認性向上が可能となります。
      これは、統合型モジュールの性能向上に直結します2

      c. メタバース関連技術
      DNPが開発中のメタバース技術を活用することで、統合型ディスプレイモジュールに新たな付加価値を付与できる可能性があります。
      例えば、XRコミュニケーション技術を組み込むことで、より没入感の高い表示が可能になります3

      d. デジタルアーカイブ技術
      DNPのデジタルアーカイブ技術を応用することで、統合型ディスプレイモジュールにコンテンツ管理機能を付加し、
      より高度な情報表示システムを構築できます4

    4. 新市場戦略
      開発した統合型ディスプレイモジュールを、スマートフォン、スマートウォッチ、ヘッドマウントディスプレイのメーカーに積極的に提案し、採用を促進します。

    これらの施策により、ジャパンディスプレイの小型ディスプレイ事業の競争力を飛躍的に高め、新たな成長機会を創出できると考えます。大日本印刷との技術提携を通じて、印刷技術とエレクトロニクス技術の融合による革新的な製品開発が可能となり、市場での優位性を確立できるものと確信しております。

  • Self-Debuggingの先駆け:bolt.new

    bolt.newは、AIを活用した革新的なWeb開発プラットフォームです。自然言語での指示だけで、フルスタックのWebアプリケーションを簡単に作成できる画期的なツールとして注目を集めています。

    AIが生み出す驚異のシミュレーション:bolt.newの実力

    最新のAI駆動型Web開発プラットフォーム、bolt.newの驚くべき能力をご紹介します。私自身がbolt.newを使って作成したシミュレーション「Kinzhal Busters」をご覧ください。このプロジェクトは、現代の軍事技術と防衛システムを模したインタラクティブな3Dシミュレーションです。

    Kinzhal Busters: https://github.com/akuroiwa/kinzhal-busters

    このシミュレーションでは、発電所に飛来するKinzhal(キンジャール)ミサイルと、それを迎撃しようとする複数のドローンによる防衛システムの動きを再現しています。Three.jsを駆使した立体的な表現により、複雑な軌道や迎撃のプロセスを視覚的に理解しやすい形で表現しています。

    bolt.newの驚異的な点は、このような高度な3Dシミュレーションを、プログラミングの詳細な知識がなくても、自然言語での指示だけで作成できることです。AIが要求を理解し、適切なライブラリやフレームワークを選択し、必要なコードを生成してくれるのです。

    Self-Debugging: エラー解決の新たなアプローチ

    bolt.newの特筆すべき機能の一つが、Self-Debuggingです。開発中に発生したエラーを、AIが自動的に解析し修正案を提示します。「Fix problem」ボタンをクリックするだけで、AIがエラーを修正し、アプリケーションを正常に動作させることができます。

    Self-Debuggingについては、論文Teaching Large Language Models to Self-Debugを参照してください。これは、これからのコード生成サービスで主流になる可能性が高い機能です。

    Viteとパッケージのインストール

    bolt.newでプロジェクトを作成すると、デフォルトでViteが選択されます。Viteは高速な開発サーバーと最適化されたビルドツールを提供する次世代のフロントエンドツールです。

    ノーコードで全てが完結する訳ではありません。Stackblitzならば自前でインストールせずともWebブラウザで確認できますが、お気に入りのエディタでコードを手直しし、気軽に動作確認したいでしょう。ここでは、その方法を説明します。

    Ubuntuでの必要なパッケージのインストール

    1. Node.jsとnpm:
    sudo apt update
    sudo apt install nodejs npm
    1. 必要に応じてNode.jsのバージョンを更新:
    sudo npm install -g n
    sudo n stable
    hash -r
    npm -v
    node -v

    npmでインストールする必要があるもの

    プロジェクトのルートディレクトリで以下のコマンドを実行します:

    npm install

    これにより、package.jsonに記載されている全ての依存関係がインストールされます。

    また、bolt.newで生成されるプロジェクトの.gitignoreファイルには、通常components/ディレクトリが含まれ、バージョン管理から除外されます。

    Viteプロジェクトの起動

    1. 開発サーバーの起動:
    npm run dev

    これにより、開発用のサーバーが起動し、通常はhttp://localhost:5173でアプリケーションにアクセスできます。
    hを入力しenterを押せば、使い方を表示してくれます。

    1. プロダクションビルド:
    npm run build

    これにより、プロダクション用のビルドが作成されます。

    1. プロダクションビルドのプレビュー:
    npm run preview

    ビルドされたプロダクションバージョンをローカルでプレビューできます。

    StackBlitzとGitHub連携

    StackBlitzは、GitHubリポジトリとの連携機能を提供しています。
    bolt.newに作成してもらったプロジェクトをGitHubリポジトリとして登録できます。
    プロジェクトの動作確認も出来るので、Webブラウザさえあれば、いつでも作業できます。

    StackblitzもNetlifyも、bolt.newと同じくGitHubアカウントでアカウント登録したりサインインしたりできます。

    bolt.newからNetlifyへのデプロイとユーザー権限移譲

    bolt.newで作成したプロジェクトをNetlifyにデプロイした直後に表示される「claim URL」をクリックすることで、
    アプリケーションの所有権があなたのNetlifyアカウントに移行されます。
    この過程で、デプロイ時に表示されたURLを控えておくことが重要です。新しい所有者がプロジェクトにアクセスする際に必要となります。

    また、GitHubで更新し、Netlifyのアプリも更新したい場合にはリポジトリの登録が必要です。

    bolt.newは、AIの力を借りてWeb開発のプロセスを大幅に簡素化し、効率化する革新的なツールです。プログラミングの経験が浅い方でも、複雑なWebアプリケーションを作成できる可能性を秘めています。

  • 「上祖師谷三丁目一家4人強盗殺人事件」の考察

    「上祖師谷三丁目一家4人強盗殺人事件」、所謂「世田谷一家殺害事件」が発生したのは2000年ですが、これを連続殺人事件と仮定すると以下のようになります。因みに、この記事の内容は既に警視庁に情報提供済みです。前半は送信した電子メールの内容で、後半のGoogle マップは今回加筆したものです。

    「上祖師谷三丁目一家4人強盗殺人事件」連続殺人の可能性について

    特別捜査本部の関係者様

    何度も電子メールを送りまして御迷惑かも知れませんので、これで一旦最後とします。
    どうか最後まで読んで下さい。

    この事件の発生する数年間に世田谷区内で4件の未解決事件の殺人事件が発生していることを前回指摘しました。

    Wikipedia「未解決事件」より抜粋:

    • 1997年11月20日 ‐ 世田谷区八幡山三丁目アパート殺人事件
    • 1998年4月8日 ‐ 世田谷区新町2丁目男性殺人事件
    • 1999年7月12日 ‐ 世田谷区新町二丁目新築工事現場内女性殺人事件
    • 2000年12月30日 – 世田谷一家殺害事件

    これらの特徴として以下の2点が挙げられます:

    1. 犯人の目撃情報がない、若しくは少ない
    2. 防犯カメラ映像がない

    以上の点から導き出した私なりの結論です:

    1. 犯人は殺害現場まで徒歩で移動した
    2. 周辺の地理や人通りに詳しい
    3. 防犯カメラの位置を熟知している

    私が想像する犯人像です。これらの内のいずれかに該当する者でしょう:

    1. 小田急電鉄小田原線の千歳船橋駅を中心とした徒歩圏内で生活できる住宅地に住む者
    2. 地元出身者、若しくは居住者
    3. 勤務地がある者

    Google マップ

    徒歩での所要時間をクリックして下さい。Google マップへのリンクです。因みに、自転車や路線バスを利用すれば移動時間はより短縮されます。

    1997年11月20日:世田谷区八幡山三丁目アパート殺人事件

    徒歩36分

    1998年4月8日:世田谷区新町2丁目路上男性殺害事件

    徒歩48分

    1999年7月12日:世田谷区新町二丁目新築工事現場内女性殺害事件

    徒歩50分

    2000年12月30日:世田谷一家殺害事件

    徒歩36分

  • Emacs入門

    Emacsの基本と開発

    チュートリアルの起動

    Emacsを起動後、以下のコマンドでチュートリアルを開始できます:

    C-h t

    日本語版を起動するには:

    C-h t japanese

    これを練習しないと、例えばマニュアルでのキーバインドの特殊な記法の意味すら理解できません。上記のキーバインドの意味が分からない方は、プルダウンのHelpメニューから辿って下さい。時間はかかりません。すぐに終わります。

    基本的な使い方

    1. 起動と終了:
      • 起動:ターミナルで emacs と入力
      • コマンドラインでの使用:emacs -nw と入力
      • 終了:C-x C-c
    2. 基本的なカーソル移動:
      • 前後左右:C-p, C-n, C-b, C-f
      • 行頭/行末:C-a, C-e
    3. ファイル操作:
      • 開く:C-x C-f
      • 保存:C-x C-s
    4. 編集:
      • コピー:M-w
      • カット:C-w
      • ペースト:C-y
    5. バッファ操作:
      • バッファ切り替え:C-x b
      • バッファ一覧:C-x C-b

    Elispでの開発方法

    1. Elispファイルの作成:.el拡張子のファイルを作成
    2. 基本的な構文:
      (defun my-function (arg)
        "Documentation string."
        (interactive "p")
        (message "Hello, %s" arg))
    3. 評価:
      • 関数全体:カーソルを関数定義の末尾に置き C-x C-e
      • バッファ全体:M-x eval-buffer
    4. デバッグ:
      • デバッガの有効化:(setq debug-on-error t)
      • ブレークポイントの設定:(debug)
      • Flycheckによるsyntaxチェック
    5. パッケージ開発:
      • provideを使用してパッケージ名を定義
      • 依存関係はrequireで指定

    極端な話、M-x load-file RETとC-h fとC-h vを知っていれば、ある程度までは試行錯誤で出来ます。まずは Programming in Emacs Lisp を読みましょう。

    load-pathloadの違い

    load-pathは、Emacsがライブラリを検索するディレクトリのリストです。新しいディレクトリを追加するには、add-to-list関数を使います。

    ;; ~/.emacs.d/init.el に記述
    (add-to-list 'load-path "~/.emacs.d/site-lisp/")

    これにより、~/.emacs.d/site-lisp/ディレクトリ内のファイルがEmacsの検索対象に追加されます。

    load関数は指定したファイルをロードします。ファイルの拡張子(通常は.el)は省略可能です。

    ;; ~/.emacs.d/init.el に上記設定に続いて記述
    ;; ~/.emacs.d/site-lisp/my-settings.el
    (load "my-settings")

    これにより、~/.emacs.d/site-lisp/my-settings.elがロードされます。

    require関数は指定したライブラリがロードされていなければロードします。provide関数とセットで使用されることが多いです。

    flycheckを有効にしていると、elispファイルの末尾でprovideを書けと注意されるので、flycheck-copy-errors-as-killでコピーすると便利です。

    ;; ~/.emacs.d/site-lisp/my-settings.el に記述
    (provide 'my-settings)
    ;;; my-settings.el ends here
    
    ;; ~/.emacs.d/init.el に記述
    ;; load-pathが通っていることが前提
    (require 'my-settings)

    設定ファイルを幾つも書いていて、まとめてloadする必要がある場合、EmacsWikiに投稿されているload-directoryを利用すると便利です。但し、load-directory.elは別のディレクトリに置いた方が良いかも知れません。以下の設定で、そのファイルを2度loadするからです。

    ;; load-pathが通っていることが前提
    (load "load-directory")
    ;; 或いは (load "~/.emacs.d/site-lisp/load-directory")
    ;; provideが書かれていれば (require 'load-directory)
    (load-directory "~/.emacs.d/site-lisp")

    以下の関数はload-directoryを元にChatGPTが書いてくれました。loadではなく、requireを再帰的に実行します。

    (defun require-directory (directory)
    "Require recursively all `.el' files in DIRECTORY."
    (dolist (element (directory-files-and-attributes directory nil nil nil))
    (let* ((path (car element))
    (fullpath (concat directory "/" path))
    (isdir (car (cdr element)))
    (ignore-dir (or (string= path ".") (string= path ".."))))
    (cond
    ((and (eq isdir t) (not ignore-dir))
    (require-directory fullpath))
    ((and (eq isdir nil) (string= (substring path -3) ".el"))
    (require (intern (file-name-sans-extension path))))))))

    以下は~/.emacs.d/init.elの設定です。

    ;; load-pathが通っていることが前提
    ;; load-directoryと同じファイル名と仮定
    ;; ~/.emacs.d/site-lisp/load-directory.el
    (load "load-directory")
    ;; provideが書かれていれば (require 'load-directory)
    (require-directory "~/.emacs.d/site-lisp")

    MELPA (Milkypostman’s Emacs Lisp Package Archive)

    MELPAは、Emacsの人気のあるパッケージリポジトリです。開発したパッケージを登録することも出来ます。プルリクエストとしてRecipeを提出する方法はREADMEを御覧ください。Pull requestsタブをクリックして書き方の参考にすると良いでしょう。

    1. MELPAの設定:
      (require 'package)
      (add-to-list 'package-archives
                   '("melpa" . "https://melpa.org/packages/") t)
      (package-initialize)
    1. パッケージのインストール:
      M-x package-install RET package-name RET
    2. パッケージの更新:
      M-x package-list-packages RET U x

    keyword-searchプロジェクト

    keyword-searchは、Emacsでブラウザスタイルのキーワード検索を可能にするパッケージです。

    1. インストール:
      M-x package-install RET keyword-search RET
    2. 基本的な使用方法:
      • M-x keyword-search RET
      • 検索エンジンを選択(TABで補完可能)
      • 検索クエリを入力
    3. カスタマイズ:
      • デフォルト検索エンジンの設定:
        M-x customize-variable RET keyword-search-default RET
      • 検索エンジンの追加:
        M-x customize-variable RET keyword-search-alist RET
    4. 拡張モード:
      • 追加の言語サービス:keyword-search-extra-mode
      • マニア向けウェブサイト:keyword-search-mad-mode

    keyword-searchは、Emacsユーザーが効率的にウェブ検索を行えるようにする便利なツールです。MELPAを通じて簡単にインストールでき、カスタマイズも容易です。

    browse-apropos-urlを元にMr. Jens Petersenが開発しました。私が書いたコードよりずっと素晴らしいです。私はプルリクエストを提出したことがきっかけで開発に参加しました。2024年現在、最後のコミットが6年前なので、動作しないURLや機能があるでしょうが、検索に役立つので是非試してください。

    プログラミングの作業の大半は調べものなのですから。

    Emacsでの定義元ジャンプと自動補完の設定

    定義元ジャンプ

    定義元ジャンプには、主に以下のパッケージが使用されます:

    1. xref: Emacsに標準搭載されているパッケージ
    2. dumb-jump: 外部ツールに依存しない汎用的なジャンプツール

    xrefの設定

    M-.xref-find-definitionsに、M-,xref-go-backに割り当てられています。xref-pop-marker-stackはEmacs 29.1で廃止されました。C-h k M-.でキーバインドを確認できます。設定されていなければ、以下のように設定し直すことが出来ます。

    (global-set-key (kbd "M-.") 'xref-find-definitions)
    (global-set-key (kbd "M-,") 'xref-go-back)

    xrefを使う前に、TAGSファイルを作成する必要があります。以下のコマンドを使用してTAGSファイルを生成します。

    Pythonでの例:

    etags --help --lang=python
    In Python code, 'def' or 'class' at the beginning of a line
    generate a tag.
    
    find . -type f -name "*.py" -exec etags -a {} +
    find /usr/lib/python3/dist-packages/ -type f -name "*.py" -exec etags -a {} +

    ctagsやetagsの拡張がaptでインストール出来ます。例えば:

    sudo apt install universal-ctags
    ls -l /usr/bin/etags
    lrwxrwxrwx 1 root root 23  3月 16  2023 /usr/bin/etags -> /etc/alternatives/etags*
    ls -l /etc/alternatives/etags
    lrwxrwxrwx 1 root root 24  7月 16 22:10 /etc/alternatives/etags -> /usr/bin/ctags-universal*

    dumb-jumpの設定

    MELPAからインストール:

    M-x package-install RET dumb-jump RET

    設定。xrefの上書き:

    (require 'dumb-jump)
    (add-hook 'xref-backend-functions #'dumb-jump-xref-activate)

    自動補完

    自動補完には、company-modeを使用します。

    MELPAからインストール:

    M-x package-install RET company RET

    設定:

    (add-hook 'after-init-hook 'global-company-mode)

    MELPAでインストールすべき便利なパッケージ

    選択候補を表示した方が早いこともあります。例えば、yank-popを視覚化したcounsel-yank-popの方が使いやすいと多くの人が感じるでしょう。私も思います。

    1. ivy1: 補完フレームワーク
      M-x package-install RET ivy RET
    2. counsel2: ivyを使用した各種コマンドの強化版
      M-x package-install RET counsel RET
    3. swiper: ivyを使用した検索機能
      M-x package-install RET swiper RET
    4. projectile: プロジェクト管理ツール
      M-x package-install RET projectile RET
    5. magit: Gitクライアント
      M-x package-install RET magit RET
    6. flycheck: シンタックスチェッカー
      M-x package-install RET flycheck RET

    flycheckの説明と設定

    flycheckは、コードの文法チェックをリアルタイムで行うツールです。多くのプログラミング言語に対応しています。

    お薦めの関数はflycheck-copy-errors-as-killです。その場のエラーをkill ringにコピーできるので、そのままyank出来ます。

    因みに、この記事ではbuilt-inのFlymakeEglotの説明をしません。

    設定:

    (add-hook 'after-init-hook #'global-flycheck-mode)

    global-flycheck-modeはあらゆる場面で起動するため、特定のメジャーモードでのみ起動する設定を推奨します。

    (add-hook 'emacs-lisp-mode-hook 'flycheck-mode)
    (add-hook 'python-mode-hook 'flycheck-mode)

    Pythonの場合、Flycheck は python-flake8 または python-pylint を使用して Python をチェックし、どちらも使用できない場合は python-pycompile を使用します(fall back)。

    Supported Languages
    pip install pylint

    lsp-modeの設定とlanguage serverのインストール

    lsp-modeのインストールと設定

    MELPAからインストール:

    M-x package-install RET lsp-mode RET

    設定例:

    (require 'lsp-mode)
    (add-hook 'python-mode-hook #'lsp)
    (add-hook 'c-mode-hook #'lsp)
    (add-hook 'javascript-mode-hook #'lsp)
    
    (add-hook 'prog-mode-hook #'lsp) ;; あらゆるprogramming modesで起動

    後者の設定はprog-mode3より派生するmajor modesに対応できるので便利です。

    Language Serverのインストール方法

    一つのプログラミング言語に対応する複数のlanguage serverがあります。

    • Python (pyright)
      npm install -g pyright
      which pyright
      /home/foo/.npm-global/bin/pyright
    • Python(jedi-language-server)
      pip install -U jedi-language-server
    • C/C++ (clangd)
      sudo apt install clangd
    • JavaScript (typescript-language-server)
      npm install -g typescript-language-server
    • Objective-C (clangd)
      sudo apt install clangd

    lspの切り替え

    C-u M-x lspつまり数引数を先に与えてlspを実行すると、language serverを切り替えることが出来ます。例えばPythonで複数のlanguage serverをインストールしている場合に便利です。

    lsp-pyrightのインストールと設定はREADMEに書かれています。

    使用しているvenvを指定するにはC-h lsp-pyright-venv-pathでcustomize this variableのリンクに入ります:

    /home/foo/.venv3.12 ;; 初期値はnil
    lsp-jediのインストールと設定もREADMEに書かれています。venvのpipでjedi-language-serverをインストールすると、lspが呼び出せませんので以下の作業が必要になります。また、Emacsで使用する前に毎回activateする必要があります。

    まず、コマンドのパスを調べます:

    source ~/.venv3.12/bin/activate # venvの例
    which jedi-language-server

    C-h v lsp-jedi-executable-commandでcustomize this variableのリンクに入ります:

    jedi-language-server ;; 変更前の初期値
    /home/foo/.venv3.12/bin/jedi-language-server ;; 変更例

    Jediを使った他の補完方法

    lsp-jediを使わずcompany-jediを使う方法もあります。

    MELPAからインストール:

    M-x package-install RET company-jedi RET

    設定:

    (defun my/python-mode-hook ()
      (add-to-list 'company-backends 'company-jedi))
    (add-hook 'python-mode-hook 'my/python-mode-hook)

    auto-completejedi.el(MELPAパッケージ名はjedi)を使う方法もあります。但し、virtualenvに依存します。aptやpipでのインストールが必要です。現在はvenvが主流ですので勘違いしないで下さい。両者は別物です。詳しくはマニュアルを参照して下さい。

    以下の作業も必要になるでしょう:

    M-x jedi:install-server RET
    M-x jedi:reinstall-server RET ;; 2回目から 

    ~/.emacs.d/.python-environments/default/に仮想環境が作られます。

    デバッグの設定と使い方

    デバッグの設定と使い方についても簡単に説明します。

    • Emacs標準のgud-modeを使用する場合
      M-x gdb
      M-x pdb ;; Pythonの場合

      pdbの場合、ミニバッファに以下のように表示されるのでファイルを指定します:

      Run pdb (like this): python -m pdb myscript.py

      gdbやpdbのコマンド若しくはメニューから操作できます。コマンドについては脚注のリンク45を参照して下さい。

    キー割り当て

    キーボードに右Altが無いと、Emacsユーザーには不便です。以下のように設定すると、変換キーをEscのように使うことが出来ます。

    ;; 「無変換」キーで定義の先頭に移動
    (global-set-key [muhenkan] 'beginning-of-defun)
    ;; MetaつまりAltを押しながら「無変換」で定義の末尾に移動
    (global-set-key (kbd "M-<muhenkan>") 'end-of-defun)
    ;; 「変換」キーをEscのようにする
    (global-set-key (kbd "<henkan>") esc-map)
    ;; 「カタカナひらがな」キーをM-xにする
    (global-set-key [hiragana-katakana] 'execute-extended-command)

    まとめ

    設定したりパッケージを導入することで、Emacsの機能を大幅に拡張し、より効率的な開発環境を構築することができます。定義元ジャンプや自動補完、シンタックスチェックなどの機能は、コーディングの生産性を大きく向上させます。

    Emacsのパッケージとは別に、aptやpipやnpmでインストールしてEmacsから呼び出すものがあるので混乱するかも知れませんが、そのソフトウェアの開発言語が何かを知っていれば、何故そのpackage managerでインストールするのか理解できるでしょう。

    Citations:
    [1] keyword-search.el
    [2] Emacsの特徴や活用方法を徹底解説!
    [3] Emacsチュートリアル 日本語訳
    [4] emacs の使い方
    [5] Emacs の簡単な使い方
    [6] #17 “手遅れ”を防ぐ Emacsのセーフガードシステム (Software Design 2015年9月号掲載記事) Emacs undo redo 使い方
    [7] 突然だがEmacs を始めよう
    [8] Programming in Emacs Lisp
    [9] EmacsでFlycheckのウィンドウをトグルできるようにした
    [10] ctagとetagについて #8
    [11] exuberant-ctagsとuniversal-ctagsの違い
    [12] Flycheck を Python で使うためにしたことメモ
    [13] Flycheck — Syntax checking for GNU Emacs

    1. helm を背に ivy の門を叩く ↩︎
    2. Vimmer から見た Emacs ファジーファインダーの歴史について ↩︎
    3. Prog Mode ↩︎
    4. 3 デバッグのお供: ”gdb のススメ” ↩︎
    5. pdb — Python デバッガ ↩︎
  • GNU nano

    GNU nanoテキストエディタの基本的な使い方

    GNU nanoは、Linuxシステムで広く使用されている、シンプルで使いやすいコマンドラインテキストエディタです。以下に、nanoの基本的な使い方を説明します。

    1. nanoの起動

    ターミナルで以下のコマンドを入力してnanoを起動します:

    nano

    特定のファイルを開く場合は、ファイル名を指定します:

    nano ファイル名

    2. 基本的な編集

    • テキストの入力:カーソル位置に直接入力します。
    • カーソル移動:矢印キーを使用します。
    • 行の先頭/末尾に移動:Ctrl+A / Ctrl+E
    • ページ上下:Ctrl+Y / Ctrl+V

    3. テキストの操作

    • 切り取り(カット):Ctrl+K
    • 貼り付け(ペースト):Ctrl+U
    • コピー:Alt+6でマーク開始、移動後Alt+6で範囲指定、Alt+6でコピー

    4. 検索と置換

    • 検索:Ctrl+W
    • 次を検索:Alt+W
    • 置換:Ctrl+\

    5. ファイルの保存と終了

    • 保存:Ctrl+O
    • 終了:Ctrl+X(変更がある場合は保存するか尋ねられます)

    6. その他の便利な機能

    • ヘルプ表示:Ctrl+G
    • 行番号表示切替:Alt+N
    • スペルチェック(要aspell):Ctrl+T

    7. nanoの設定

    ~/.nanorc ファイルを編集することで、nanoの動作をカスタマイズできます。例:

    set autoindent
    set tabsize 4
    set linenumbers

    nanoは直感的で学習曲線が緩やかなため、初心者にも扱いやすいエディタです。これらの基本的なコマンドを覚えれば、多くの編集作業をスムーズに行うことができます。より高度な機能については、nanoのマニュアル(man nano)を参照してください。

    Citations:
    [1] nano Command Manual
    [2] GNU nano
    [3] Nano
    [4] A Beginner’s Guide to Using the GNU nano Text Editor on Linux

  • Pythonパッケージをソースからインストールする

    Gitリポジトリからのpythonパッケージインストール方法

    GitHubやその他のバージョン管理システム(VCS)のリポジトリから直接Pythonパッケージをインストールすることができます。これは、まだPyPIに公開されていないパッケージや、最新の開発バージョンを使用したい場合に特に便利です。

    Gitリポジトリからpythonパッケージをインストールする方法には、主に2つのアプローチがあります:リモートリポジトリから直接インストールする方法と、ローカルにクローンしたリポジトリからインストールする方法です。

    リモートリポジトリから直接インストール

    基本的な使用方法

    pip install git+https://github.com/username/repository.git

    具体的な例

    1. 公開リポジトリからのインストール:
    pip install git+https://github.com/numpy/numpy.git
    1. 特定のブランチやタグからインストール:
    pip install git+https://github.com/username/repository.git@branch-name
    pip install git+https://github.com/username/repository.git@v1.0
    1. サブディレクトリにあるパッケージのインストール:
    pip install git+https://github.com/username/repository.git#subdirectory=package_dir

    プライベートリポジトリからのインストール

    プライベートリポジトリからインストールする場合、認証が必要です。

    1. HTTPSを使用する場合:
    pip install git+https://username:password@github.com/username/repository.git

    注意: パスワードをコマンドラインに直接入力することは推奨されません。代わりに、個人アクセストークンを使用することをお勧めします。

    1. SSHを使用する場合:
    pip install git+ssh://git@github.com/username/repository.git

    SSHキーの設定が必要です。

    requirements.txtでの使用

    requirements.txtファイルでGitHubリポジトリを指定することもできます:

    git+https://github.com/username/repository.git@v1.0

    ローカルにクローンしたリポジトリからインストール

    このアプローチは、リポジトリをローカルマシンにクローンし、そのディレクトリに移動してインストールする方法です。

    手順

    1. リポジトリをクローン:
    git clone https://github.com/username/repository.git
    1. クローンしたディレクトリに移動:
    cd repository
    1. パッケージをインストール:
    pip install .

    具体的な例

    git clone https://github.com/username/my-project.git
    cd my-project
    pip install .

    開発モードでのインストール

    パッケージを開発中で、ソースコードを編集しながらテストしたい場合は、開発モードでインストールすることができます:

    pip install -e .

    -eオプション(または--editable)を使用すると、パッケージがソースディレクトリにリンクされ、ソースコードの変更がすぐに反映されます。

    注意点

    • どちらの方法でも、リポジトリにはsetup.pyまたはpyproject.tomlファイルが含まれている必要があります。
    • ローカルにクローンする方法は、パッケージのソースコードを確認したり、修正を加えたりする場合に特に便利です。
    • 開発モードでのインストールは、自作のパッケージを開発する際に非常に有用です。
    • セキュリティ上の理由から、信頼できるソースからのみインストールしてください。
    • 依存関係の管理に注意が必要です。特に、複数のプロジェクトで作業している場合は、仮想環境の使用を検討してください。

    まとめ

    GitリポジトリからPythonパッケージをインストールする方法は、開発中のパッケージや、まだPyPIに公開されていないパッケージを使用する際に非常に便利です。リモートからの直接インストールとローカルにクローンしてからのインストールの両方の方法を理解しておくことで、様々な状況に対応できます。

    Citations:
    [1] Python のビルドとテスト
    [2] Python配布パッケージをGitHubリポジトリ経由でインストールする方法(PublicとPrivate両パターン)
    [3] setup.pyのないGitHubリポジトリからライブラリをimportする方法
    [4] GitHub のプライベートリポジトリから Python の独自パッケージをインストールしてみた
    [5] 【Python】GitHubから直接パッケージをインストールする方法
    [6] GitHub のリポジトリを requirements.txt に含める

  • Python 3.12でのパッケージング手法の変更

    Python 3.12におけるパッケージングの変更と pandas_datareader のインストール問題

    Python 3.12では、パッケージングシステムに大きな変更が加えられました。これにより、一部のライブラリのインストールに影響が出ています。特に pandas_datareader のインストール時に遭遇する可能性のあるエラーと、その解決方法について説明します。

    pandas_datareader のインストール問題

    Python 3.12で pandas_datareader をインストールしようとすると、以下のようなエラーが発生する可能性があります:

    ModuleNotFoundError: No module named 'distutils'

    このエラーは、Python 3.12で setuptools が必要になったことが原因です。setuptools は以前は distutils モジュールに依存していましたが、Python 3.12ではこのモジュールが削除されました1

    解決方法

    この問題を解決するには、以下の手順を試してください:

    1. setuptools を最新版にアップグレードする:
    pip install --upgrade setuptools
    1. pandas_datareader をインストールする:
    pip install pandas_datareader

    Numpy のビルドシステム変更

    Python 3.12では、Numpy のようなライブラリでもビルドシステムの変更が行われています。Numpy は Python 3.12 でデフォルトのビルドシステムを meson build system に移行しました2。これにより、setuptools の使用は非推奨となり、将来的には廃止される予定です。

    pyproject.toml の推奨

    パッケージングで pyproject.toml が強く推奨されている理由の一つは、このようなビルドシステムの変更に対応するためです。pyproject.toml を使用することで、プロジェクトのビルドシステムやその依存関係を明確に指定できます。

    以下は pyproject.toml の簡単な例です:

    [build-system]
    requires = ["setuptools>=61.0", "wheel"]
    build-backend = "setuptools.build_meta"
    
    [project]
    name = "example_project"
    version = "0.1.0"
    description = "An example project"
    dependencies = [
        "pandas",
        "numpy",
    ]
    
    [project.scripts]
    my-script = "example_project.cli:main"

    console_scripts と名前空間

    pyproject.toml の [project.scripts] セクション(または setup.py の entry_points)で指定される console_scripts は、モジュールパスとコロンで区切られた関数名を使用します。

    例えば、example_project.cli:mainexample_project/cli.py ファイル内の main() 関数を指しています。

    この指定方法はクラス定義内のメソッドにも適用できます。例えば:

    class CLI:
        @staticmethod
        def main():
            print("Hello from CLI!")

    この場合、pyproject.toml では以下のように指定できます:

    [project.scripts]
    my-script = "example_project.cli:CLI.main"
  • Pythonのパッケージの作成と登録

    setup.pyとpyproject.tomlの関係

    setup.pyとpyproject.tomlの役割

    setup.pyは長い間、Pythonパッケージのビルドと配布のための標準的な設定ファイルとして使用されてきました。しかし、近年ではpyproject.tomlが推奨されています。pyproject.tomlは、パッケージングツールやその他のツールの設定を一元管理するためのファイルです。

    pyproject.tomlの利点

    1. ツールの統一:
      pyproject.tomlは、ビルドシステムの依存関係やプロジェクトのメタデータを一つのファイルにまとめることができます。これにより、プロジェクトの設定が一元化され、管理が容易になります。

    2. ビルドシステムの宣言:
      [build-system]テーブルを使用して、プロジェクトのビルドに必要なツールや依存関係を明示的に宣言できます。これにより、ビルド環境の再現性が向上します。

    3. ツール間の互換性:
      pyproject.tomlは、setuptoolspoetryflitなどの異なるビルドツールと互換性があります。これにより、特定のツールに依存せずにプロジェクトを管理できます。

    setup.pyは不要か?

    新しいプロジェクトでは、pyproject.tomlを使用することが強く推奨されています。特に、ビルド中にカスタムスクリプトを実行する必要がない場合、setup.pyは最小限のスタブとしてのみ使用されるべきです。具体的には、以下のように最小限のsetup.pyを使用できます:

    # setup.py
    import setuptools
    setuptools.setup()

    具体的な設定例

    以下に、pyproject.tomlの具体的な設定例を示します:

    [build-system]
    requires = ["setuptools", "wheel"]
    build-backend = "setuptools.build_meta"
    
    [project]
    name = "your-package-name"
    version = "0.1.0"
    description = "A short description of your package"
    authors = [
        { name = "Your Name", email = "your.email@example.com" }
    ]
    dependencies = [
        "requests >= 2.0.0",
        "numpy >= 1.18.0"
    ]
    
    [tool.black]
    line-length = 88

    PyPIへのパッケージ登録手順

    1. TestPyPIでのテスト:

      • TestPyPIにアカウントを作成し、APIトークンを取得します。
      • パッケージをビルドし、TestPyPIにアップロードしてテストします。
    2. APIトークンの取得:

      • PyPI(またはTestPyPI)のアカウント設定からAPIトークンを生成します。
    3. .pypircファイルの設定:

      • ホームディレクトリに.pypircファイルを作成し、以下のように設定します:
    [distutils]
    index-servers =
        pypi
        testpypi
    
    [pypi]
    username = __token__
    password = <Your-PyPI-API-token>
    
    [testpypi]
    username = __token__
    password = <Your-TestPyPI-API-token>
    1. パッケージのビルドとアップロード:
      • python -m buildコマンドでパッケージをビルドします。
      • python -m twine upload --repository testpypi dist/*でTestPyPIにアップロードします。
      • テストが成功したら、python -m twine upload dist/*で本番のPyPIにアップロードします。

    まとめ

    最新の情報では、pyproject.tomlが推奨されています。特に新しいプロジェクトでは、pyproject.tomlを使用することで、設定の一元管理やビルド環境の再現性が向上します。setup.pyは最小限のスタブとして使用し、主要な設定はpyproject.tomlに記述することが推奨されます。

    Citations:
    [1] Pythonで自作ライブラリを作るとき、setup.pyに代えてpyproject.tomlを使ってみませんか?
    [2] pyproject.toml を書く
    [3] Should pyproject.toml configs always be required to use poetry? #3443
    [4] Should I be using only pyproject.toml? [closed]
    [5] pyproject.toml specification

  • Pythonの仮想環境(venv)とパッケージ管理(pip)の基本

    1. 仮想環境(venv)とは

    仮想環境は、プロジェクトごとに独立したPython環境を作成するためのツールです。これにより、異なるプロジェクトで異なるバージョンのパッケージを使用することができます。

    2. 仮想環境の作成と使用

    仮想環境の作成

    # プロジェクトディレクトリに移動
    cd my_project
    
    # 仮想環境の作成
    python3 -m venv venv

    仮想環境の有効化

    # Unix/macOS
    source venv/bin/activate
    
    # Windows
    venv\Scripts\activate

    仮想環境の無効化

    deactivate

    3. パッケージ管理(pip)

    pipの基本

    pipはPythonのパッケージ管理ツールで、パッケージのインストール、アップグレード、アンインストールを行います。

    パッケージのインストール

    pip install package_name

    パッケージのアップグレード

    pip install --upgrade package_name

    パッケージのアンインストール

    pip uninstall package_name

    インストール済みパッケージの一覧表示

    pip list

    パッケージの詳細情報

    pip show package_name

    4. requirements.txtの使用

    requirements.txtの作成

    プロジェクトで使用しているパッケージを一覧にして、他の開発者が同じ環境を再現できるようにします。

    pip freeze > requirements.txt

    requirements.txtからパッケージをインストール

    pip install -r requirements.txt

    5. パッケージの作成と配布

    パッケージの構成

    以下では従来の方法を説明します。強く推奨されているpyproject.tomlについては1別の機会に説明します。

    パッケージを作成するためには、以下のようなディレクトリ構造が必要です:

    my_package/
    ├── my_package/
    │   ├── __init__.py
    │   └── module.py
    ├── setup.py
    └── README.md

    setup.pyの例

    通常、ソフトウェアの開発はパッケージのビルドを前提としているファイルとパスの構成になっていますので、GitHub等で参考となるプロジェクトの書き方を手本とするのが早道です。参考になるかどうかはわかりませんが、私の管理するプロジェクトのレポジトリはこちらです。

    console_scriptsは、例えばLinuxならばシェルコマンドとして動作します。仮想環境が~/.venv3.12ならば、~/.venv3.12/bin/以下にインストールされます。コマンドとして呼び出したい関数を指定します2

    from setuptools import setup, find_packages
    
    setup(
        name='my_package',
        version='0.1',
        packages=find_packages(),
        install_requires=[
            'requests',
        ],
        entry_points={
            'console_scripts': [
                'my_command=my_package.module:main',
            ],
        },
    )

    パッケージのビルドと配布

    Pythonパッケージユーザーガイド(Python Packaging User Guide)をまず読みましょう。以下のコマンドでは非推奨となった方法も併記します3

    # パッケージのビルド(非推奨となった。旧式)
    python setup.py sdist bdist_wheel
    
    # 推奨
    python -m build
    
    # PyPIにアップロードするためのツールをインストール
    pip install twine
    
    # パッケージのアップロード
    twine upload dist/*

    6. Gitと仮想環境の管理

    .gitignoreの設定

    仮想環境のディレクトリをGitの管理対象から除外するために、.gitignoreファイルに以下を追加します。GitHubからコピーしてくると良いでしょう4

    venv/

    まとめ

    この記事では、Pythonの仮想環境(venv)とパッケージ管理(pip)の基本的な使用方法について説明しました。仮想環境を使用することで、プロジェクトごとに独立した環境を作成し、依存関係の管理が容易になります。また、pipを使用してパッケージのインストールや管理を行うことで、開発効率を向上させることができます。さらに、requirements.txtを使用して環境を再現可能にし、setup.pyを使用してパッケージを作成・配布する方法も紹介しました。

    1. どうすれば setup.py ベースのプロジェクトを近代化できるでしょうか? ↩︎
    2. 9.2. Python のスコープと名前空間 ↩︎
    3. setup.py は非推奨になりましたか? ↩︎
    4. Python.gitignore ↩︎