本プロジェクトは、論文で提案する「PWV with Multi-Version Objects (MVO)」の PoC トランスパイラです。Python の AST を解析し、バージョン付きクラス群を統合クラスに変換して実行します。
- Python 3.12 以上
- uv: 高速なパッケージインストーラ/リゾルバ
# Python バージョン固定 (.python-version を作成)
uv python pin 3.12
# 依存関係インストール (.venv と uv.lock が無ければ作成)
uv syncuv sync の内容
- .venv を作成
- 依存関係をインストール
- プロジェクトを editable でインストール(src/mvo_compiler を import 可能にする)
# macOS/Linux
source .venv/bin/activate
# Windows PowerShell
.venv\Scripts\activate
# deactivate
deactivateベンチマークは本体とは別の仮想環境で実行できます。bench 依存グループを用意しているので、専用の venv を作って同期してください。
# ベンチマーク用の仮想環境を作成
uv venv .venv-bench
# アクティベート
.venv-bench\Scripts\activate
# ベンチマーク依存のみ同期
uv sync --group bench --active通常の環境に追加したい場合は、既存の venv で uv sync --group bench --active を実行してください。
# 例: test/resources/basic_cases/TEST_basic_01/sources を実行
python main.py test/resources/basic_cases/TEST_basic_01/sources
# デバッグログを有効化
python main.py test/resources/basic_cases/TEST_basic_01/sources --debug
# バージョン選択戦略を指定
python main.py test/resources/basic_cases/TEST_basic_01/sources --strategy latest- target_dir は main.py 内の
INPUT_BASE_PATHからの相対パスです。- 現状の
INPUT_BASE_PATHはリポジトリルート(.)です。
- 現状の
- strategy は continuity | latest を選択します。
compile() に渡すディレクトリ配下を再帰的にスキャンします。
- **/*.py はソースファイル
- **/*_sync.py は同期モジュール
- **/*.json は互換性(属性)定義
- 同一ベース名のバージョンは同一ファイルに定義します。
- クラス名は
<BaseName>__<version>__形式で、version は整数です。 - クラス定義はトップレベルメソッドのみを対象にします。
- クラス属性(AnnAssign/Assign)は無視されます。
- 内部クラスは未対応です。
例
class Point__1__:
def __init__(self, x: int):
self.x = x
class Point__2__:
def __init__(self, r: float):
self.r = r- バージョン付きクラスは通常クラス/バージョン付きクラスを継承できます。
Foo__2__のようにバージョン付きクラスを継承した場合、バージョン情報も継承関係として記録されます。
- ファイル名は
<BaseName>_sync.pyです(例: Point_sync.py)。 - 位置は入力ディレクトリ配下ならどこでも構いません。
- 同期関数名は
_?sync_from_v<from>_to_v<to>形式です。先頭の_は任意です。 - 同期関数の引数は 1 つ(wrapper オブジェクト)です。
- 同期モジュール内の import 文は統合クラスの先頭へ移されます。
例
def _sync_from_v1_to_v2(wrapper_obj):
wrapper_obj._v2 = "Version 2"
del wrapper_obj._v1入力ディレクトリ配下の任意の .json を読み込みます。
スキーマ
{
"<BaseName>": {
"<version>": ["attr1", "attr2"]
}
}<version>は整数の文字列です。
main.py 経由で実行する場合、入力ディレクトリ直下に main.py が存在することを想定します。
- テストケース: test/resources/**/TEST_*/ 以下
- 入力サンプル: test/resources/**/TEST_*/sources/
- 期待出力: test/resources/**/TEST_*/outputs/output.txt
# 全テスト
pytest
# 特定のテストのみ
pytest --target_dir=basic_cases/TEST_basic_01.
├── main.py
├── pyproject.toml
├── src/
│ └── mvo_compiler/
│ ├── mvo_compiler.py
│ ├── scanner.py
│ ├── transformer.py
│ ├── builder/
│ ├── symbol_table/
│ ├── util/
│ └── templates/
└── test/
├── conftest.py
├── test_create.py
├── test_transformer.py
└── resources/
├── basic_cases/
│ └── TEST_basic_01/
│ ├── sources/
│ └── outputs/
└── features/
└── ...