AKAGI Rails

鉄道模型シミュレーターで遊んでいたはずが、気づいたらPythonなども。

VRMNXで使う汎用モジュールをどこに保存するか

普通のPythonであれば,pipというパッケージ管理ツールで,サードパーティのモジュールやパッケージを使うことができるようになりますが,VRMNXに搭載されているPythonエンジンではそういう便利なことはできません。撮る夫くん などのVRMNX用汎用モジュールは、レイアウトファイルと同じ場所にpyファイルを保存することで,importできるようになります。しかし、撮る夫くんを多数のレイアウトで使うたびにいろんなフォルダにtoruo.pyをコピーするのは面倒です。

これを回避して楽をする方法も存在します。Pythonのインポートシステムの解説も交えながらその方法を説明するとともに、Python拡張を利用するVRMNXレイアウトの配布や利用の指針を提案したいと思います。

Pythonのインポートシステム

例えば,よく使われる標準モジュールに,乱数を扱うrandomがあります。Pythonimport randomという文を実行する際は、モジュール検索パスの場所を順番に探して、見つかったrandom.pyをインポートしています。

このあたりの細かい仕様は,Python公式マニュアルに記述があるので興味のある方はご覧ください。以下では,利用者目線で必要な事柄をかいつまんで紹介します。

モジュール検索パス

さて、Pythonがモジュールを探しに行く場所を、 モジュール検索パス といいます。 これを確認してみましょう。

import sys
for p in sys.path:
    vrmapi.LOG(p) #VRMNXのPythonエンジンの場合
    print(p) # 普通のPythonの場合

sys.pathにはリスト形式でいくつかのパスが収められており,このリストの先頭からモジュールを検索します。同名のモジュールがあった場合には,最初に見つかったモジュールがimportされ,それ以降のパスの検索は中止されます。

VRMNXのPythonエンジンの場合,最初の3つは

 C:\\Program Files\\I.MAGIC\\鉄道模型シミュレーターオンラインNX\\python\\Lib
 C:\\Program Files\\I.MAGIC\\鉄道模型シミュレーターオンラインNX\\python\\Lib\\site-packages
 C:\\Users\\yourname\\AppData\\Roaming\\imagic\\vrmonline\\python\\Lib

のようになっているはずです(VRMNX Version 6.0.0.210)。このうち1つ目は,先程のrandom.pyなどの標準モジュールを収めておくディレクトリであり,先程のrandomモジュールはここから読み出されます。

そして,どこかに保存済みのレイアウトでこれを実行していれば,4つ目に,レイアウトを保存したディレクトリが来ていると思います。したがって,レイアウトと同じ場所にモジュール(またはパッケージ)を保存しておけば,Pythonエンジンがそのモジュールを探し出して,無事importが行われるわけです。

しかし当然,モジュール検索の仕様上,リストにある他のフォルダにモジュールやパッケージを置いておくことでも,Pythonエンジンからimportできるようになります。ただし,python/Libとpython/Lib/site-packagesの違いについて留意しておくことが必要です。python/LibにはPythonの標準モジュールの置き場なので,サードパーティのモジュールやライブラリはsite-packagesに収めるべきです。

site-packagesにモジュールをインストールしたら,配布時のバージョン管理に注意

pythonパッケージには作者によってアップデートが入る可能性があります。例えば,私が新バージョンの撮る夫くんを同梱してレイアウトを配布したとして,それをダウンロードしたユーザの C:\Program Files\ 以下に旧バージョンの撮る夫くんがインストールされていた場合,VRMNXシステムは私のレイアウトからでも旧バージョンの撮る夫くんを優先的にインポートします。これでは不都合が生じる可能性があります。

このことを回避するためには,システムのモジュール検索パスの先頭にレイアウトのディレクトリを強制的に指定してしまえばよく,次のような記述をレイアウトスクリプトの先頭に書き加えることで対応できます。

#LAYOUT
import os, sys
import vrmapi
sys.path.insert(0, os.path.abspath(vrmapi.SYSTEM().GetLayoutDir()))

外部モジュールを同梱してレイアウトを配布する際には,この一手間を加えてやるのが安心です。

なお, sys.path.insert(0, <somewhere>)というイディオムは,Pythonモジュールのリファレンス文書を自動生成してくれるSphinx-apidocのconf.pyや,pipの内部仕様にも見られ,割とポピュラーなものです。

まとめ

  • 撮る夫くん(toruo.py)などの汎用モジュール(汎用パッケージ)は, C:\Program Files\I.MAGIC\鉄道模型シミュレーターオンラインNX\python\Lib\site-packages に保存すべし。
  • 外部モジュールに依存したレイアウトを作って配布するときには,レイアウトと同じフォルダにモジュールを保存すべし。

自作車両第二弾、完結

昨年7/31に先行リリースした731系に加えて、2/01にキハ201系をリリースしまして、自作車両第二弾は一応完結ということになりました。 ブログでの告知がすっかり遅くなってしまいました。

中身についてはVRM Terminalダウンロードページでたっぷりご覧ください。

f:id:AKAGI-vrmstation:20210217010835j:plain

せっかくなので、ブログではこの形式を選んだ経緯みたいなものをご紹介しましょう。

ダウンロードページから察しがついた方もあるかもしれませんが、結論から言ってしまえば、音楽館が昔出していた Train Simulator JR北海道① (函館本線余市〜小樽〜札幌)がAKAGIとこれらの形式の出会いでした。15年以上は前です(いくつだよオレ)

f:id:AKAGI-vrmstation:20210217151046j:plain

963D普通列車で小樽に到着すると731系とキハ201系の連結シーンが見られるというボーナス(?)が付いていました。これが物珍しい感じで好きでしたね。

運転ゲームにハマり直すまでずっと放置してたので、試験モードをクリアしたのは数年前と割と最近。音楽館のゲームはとにかく辛めな仕上がりで難しいのです。快速列車はまだマシですが、普通列車の山線区間は制限が多い上にダイヤがかなりキツかった。小樽では連結を含めて停車時間が10分あるので待たなくてはいけない(飛ばせない)ので、パソコンを離れて休憩してたら時間過ぎててダメになったりもしました(笑)

なんの役にも立たない思い出話をしてしまいましたが、このゲームの雰囲気を見ることができるYouTube動画を発掘しました。カッコいいオープニングと、先程も出てきた連結シーン(22分15秒~)は、ぜひとも音付きでご覧頂きたい。

このゲームもWindows95/98世代のものですから今のWindows 10では動かそうとしたことすらありませんね。動くんでしょうかね?流石にもういいですけどね(笑)

VRMNXで大型レイアウトを遊ぶときのJITレンダリングの設定について

あけましておめでとうございます。2021年もよろしくおねがいします。

さて、VRMデータ広場で先日公開となった、shirokuma氏の「複線レイアウト」をVRMNXで開いて遊ぼうと思ったところ、トラブルに遭遇しました(それで、冬休み最後の貴重な時間を4時間も溶かして解決した)ので備忘録的に書き留めておきます。

分かってしまえば簡単に解決可能なトラブルだったので、みなさんぜひ「複線レイアウト」をお手元の環境で鑑賞してみてください。4時間かけて見てみる価値のあるレイアウトでした。

続きを読む

Twitterウィジェットをクラウドから #VRMポータル #試運転中

VRMポータルでご提供しているTwitterウィジェットは、PythonプログラムでTwitter APIを叩いてツイートを収集する仕組みです。しかし最近、プログラムをホストしていたAndroidタブレットの調子が悪くてしばしば収集が停止していました。

(プログラム自体はシンプルで、動く環境さえあればいい、という感じなので、タブレットで24時間稼働させていました。USB電源で動きますしファンの音もしないのでこれはこれで良かったのです。動きさえすれば。)

最近の流行に乗っかって、Google Cloud Platformに乗せ換えることにしました。最近流行りの、クラウドコンピューティングです。

  • AWSにしろGCPにしろ、機能が色々ある・組み合わせて使うことが前提であるため、なかなか複雑で分かりにくい
  • 無料で使える使用枠もあるものの、回したいシステムがどのくらい負荷があるか、無料枠に収まるかどうかが分かりにくい

という不安要素もありますが、まずは試運転という感じです。

仕組みとしては、

  1. Cloud Scheduler で、毎日決まった時刻にPub/Subのトピックを起動する
  2. トピックをトリガーにCloud Functionsに作成したPythonプログラムが呼び出される

このPythonプログラムは、これまでローカルで動いていたものとほとんど同じです。

Sphinx-automodapiでVRMNX用パッケージのリファレンスを作る

ATENXAという名前で、VRMNXpy用のパッケージを計画中です。

f:id:AKAGI-vrmstation:20201013234850p:plain

汎用ライブラリとしてもお使いいただける機能があるので、リファレンスマニュアルを準備したいのですが、その方法をいつも忘れては調べ直している(そして、そこそこ時間がかかる)ので、備忘録として書き残しておきます。おきましたが、直後に結局方策を改めたので、以下、全面的に書き換えました。(9/22)

経過のあらまし

  • 当初、Sphinx-apidocでのドキュメント作成を計画した。
  • apidocは複雑なimport関係をもつパッケージのドキュメント化に向かないことが分かった。
  • Sphinx-autosummaryをプランBとして検討したが、構文解析中のImportError (atenxaがimportできない) により、断念した。(ディレクトリ構成は合っているはずなのだが…)
  • サードパーティSphinxむけドキュメント生成ツールとして、Sphinx-automodapiを見つけた。ユーザが使用するときのパッケージの階層構造の見た目に適応してドキュメントを作ることができるとのことで、これを採用した。

必要なもの

restructured-text (reST) や Markdown をビルドしてhtmlにしてくれる。公式ドキュメントは日本語訳が中途半端で、かつ、オリジナルの英語版も難解であり、そして、巷間のブログの情報も(少なくとも日本語では)上質なものが少ないが、Python関係のドキュメントといえばデファクト・スタンダードとなっている。Pythonパッケージとして動作するので

pip install sphinx

する。

sphinx-automodapi.readthedocs.io

これも同様に、

pip install sphinx-automodapi

する。

  • HTMLテーマ

書き出されたHTMLドキュメントの見た目のプリセットがいろいろ配布されている。有名どこだと、Read the Docsとか。

今回は、I.MAGIC御用達のMaterial for MkDocsをオマージュしたMaterial for Sphinxを使う。

pip install git+https://github.com/bashtage/sphinx-material.git
  • ダミーの vrmapi.py

VRMNX用の拡張モジュールなので、どうしてもvrmapiモジュールに依存する。しかしこれが、通常使われるPythonシステムのsite-packagesにはないので、Sphinxのパーサーが一度ATENXAのコードを実行するときに ImportError: No module 'vrmapi' was found. が出てしまう。このエラーを回避するため、ダミーのvrmapi.pyを作っておく。

このエラーは、autodocに対しては、autodoc_mock_importsオプションによってどうやら回避できるらしい。automodapiに対する回避策として適当かは未検証である。しかし、Visual Studio Code(のPython拡張)の字句解析上のエラーメッセージを封じるためにもある程度有用なので、作っておくとよい。

# -*- coding: utf-8 -*-
def LAYOUT():
    return None

def SYSTEM():
    return None

def LOG(obj):
    return

def CLEARLOG():
    return

def ImGui():
    return None

フォルダ構成

ATENXA-0.1.0alpha
├── docs
├── atenxa
│ ├── __init__.py
│ └── (他いろいろ)
├── vrmapi.py (ダミーのやつ)
└── (テスト用の.vrmnxとかいろいろ)

Sphinx のセットアップ(最初だけ)

./docs 以下にSphinx関係のもろもろをセットアップする。コマンドライン

cd docs
sphinx-quickstart

を実行すると、対話形式でいろいろ聞かれる。

Welcome to the Sphinx 1.7.1 quickstart utility.

Please enter values for the following settings (just press Enter to
accept a default value, if one is given in brackets).

Selected root path: .

You have two options for placing the build directory for Sphinx output.
Either, you use a directory "_build" within the root path, or you separate
"source" and "build" directories within the root path.
> Separate source and build directories (y/n) [n]: y

... 途中省略

For a list of supported codes, see
http://sphinx-doc.org/config.html#confval-language.
> Project language [ja]: (ENTER)

... 以下省略
  • sourceとbuildのフォルダを分けるかと聞かれるが、分けておいたほうが整理できてよい。
  • 言語を聞かれたら、jaで日本語になる。

初期設定

sphinx-quickstartをすると ./docs に色々フォルダやファイルが生成される。 そのなかで、 ./docs/souce/conf.py./docs/source/index.rst を編集する。

conf.py の設定

冒頭のコメントアウトされている3行を戻す。3行目はちょこっと編集して、atenxaパッケージとvrmapi.pyが見えるトップディレクトリを参照している。(conf.pyからの相対参照である。)

import os
import sys
sys.path.insert(0, os.path.abspath('../../'))

必要なSphinx拡張を有効化する。

extensions = [
    #'sphinx.ext.autodoc',
    #'sphinx.ext.autosummary',
    'sphinx_automodapi.automodapi',
    'sphinx.ext.napoleon',
    'sphinx.ext.viewcode',
    'sphinx.ext.todo',
    'recommonmark',
]

Sphinx拡張のオプションを設定する。

source_suffix = {
    '.rst': 'restructuredtext',
    '.md': 'markdown',
}

#autodoc_mock_imports = ['vrmapi']
#autodoc_member_order = 'bysource'
napoleon_use_rtype = False
todo_include_todos = True

テーマにsphinx-materialを指定し、細かい設定をいくつか。

html_theme = 'sphinx_material'

# Material theme options (see theme.conf for more information)
html_theme_options = {

    # Set the name of the project to appear in the navigation.
    'nav_title': 'ATENXA',

    # Set you GA account ID to enable tracking
    #'google_analytics_account': 'UA-XXXXX',

    # Specify a base_url used to generate sitemap.xml. If not
    # specified, then no sitemap will be built.
    #'base_url': 'https://project.github.io/project',

    # Set the color and the accent color
    'color_primary': 'red',
    'color_accent': 'yellow',

    # Set the repo location to get a badge with stats
    #'repo_url': 'https://github.com/project/project/',
    #'repo_name': 'Project',

    # Visible levels of the global TOC; -1 means unlimited
    'globaltoc_depth': 3,
    # If False, expand all TOC entries
    'globaltoc_collapse': False,
    # If True, show hidden TOC entries
    'globaltoc_includehidden': False,
}

index.rst の設定

indexでなくてもよいのだが、関数とその概要の一覧表を入れたい箇所に

.. automodapi:: atenxa
    :no-inheritance-diagram:

こんなのを書いておく。(TOCtreeと同じ要領である。)

ドキュメントのビルド

./docsで

make clean make html

1行目で./docs/buildを一度きれいに空にして、改めてhtmlをビルドする。

./buildにHTMLなど必要なものが書き出されるので、まとめてFTPでアップすればよい。

f:id:AKAGI-vrmstation:20201013235108p:plain

かなり良くできているSphinx-automodapiであるが、唯一心配なのは、あまりに知名度が低いことである。

参考

sphinx-rtd-tutorial.readthedocs.io

bashtage.github.io

www.sphinx-doc.org

www.sphinx-doc.org

Pydoc-Markdown をお試し

Pythonのdocstringを自動でドキュメント化するときはSphinxが定番ですが,それに代わるPydoc-Markdownというのを見つけたので,備忘録がてら紹介します。

pypi.org

インストール

pipからインストールできます。pipxでのインストールが推奨されています。私は無視して普通にpipでインストールしましたが,言われたとおりにするとしたら

pip install pipx
pipx install pydoc-markdown

どうせ必要になるので,MkDocsも入れておきます。MkDocs-Materialも。

お試し

Pydoc-MarkdownのGithubからまるごとダウンロードしてきて,Pydoc-MarkdownでPydoc-Markdownのドキュメントを作ってみます。

pydoc-markdown-develop (pydoc-markdown.yamlとかreadme.mdがあるディレクトリ) でターミナルを開き,次のコマンドを実行すると,ブラウザが立ち上がりlocalhostでドキュメントが読めます。

pydoc-markdown  --watch-and-serve -o

もう少し詳しく

pydoc-markdown.yaml の中身を見てみると,ここでドキュメントの構造をはじめいろいろなオプションを設定していることが分かります。

pydoc-markdown.yamlのひな型は

pydoc-markdown --bootstrap-mkdocs

で生成できます。

ただしコイツの書き方の詳しいところが私もよく分かっていません。pydoc-markdown-develop/pydoc-markdown.yamlを雰囲気でマネするのがいいかも。

HTML化

./docs/build をさらにMkDocsでビルドすると,HTMLドキュメントにできます。手順はCaldia氏のMkDocsマニュアルが参考になりますのでご参照ください。

蛇足

VRMNXpy用の拡張パッケージを作れないかと思っていろいろ試していますが,マニュアル作りのことも考えておかないといけません。 しかしSphinxではコードを一通り実行してdocstringを整形するので,実行中にvrmapiのImportErrorが出ると止まってしまい,うまくいきません。

その点Pydoc-Markdownは,コードを実行せずにdocstringをパースして整形してくれるので,この問題を回避できる…と思われたのですが,謎のエラーに遭遇しておりこちらもうまくいっていません。