🐈

起動中のMayaでPytestを実行する

2023/11/15に公開

目的

MayaでPytestを実行する時は通常下記の様にコマンドプロンプトで実行する。

mayapy -m pytest

しかし、この方法だと毎回standalone起動が必要となり、テストに時間がかかるため、起動中のMayaでPytestを実行したくなった。

実行できない

普通にスクリプトエディターで実行しても下記エラーが発生し、できない。

import pytest
pytest.main(["テストフォルダ"])

# INTERNALERROR>     self.isatty = file.isatty()
# INTERNALERROR> AttributeError: 'maya.Output' object has no attribute 'isatty'

これはMayaがstdoutクラスを独自設定しているため。

import sys
sys.stdout
# 結果: <maya.Output object at 0x000001F42EE539B0>

解決方法

ドンピシャな方法がissueに上がっていて、StdOutクラスをラップしてあげれば良さそう。
https://github.com/pytest-dev/pytest/issues/5462

上記のissueを参考に書いた物がこちら。

import sys
import pytest
from maya import cmds

class MayaStdOutWrapper:
    """stdoutをラップする
    """    
    def __init__(self, stdout):
        self._stdout = stdout

    def __getattr__(self, item):
        if item == "isatty":
            return self.isatty
        else:
            return getattr(self._stdout, item)

    def isatty(self):
        return False

def reload_tests(test_packages_name: str):
    """なくても動くが
    pytestを一度実行した前にリロードしないと修正内容が反映されない
    """    
    for module_name in list(sys.modules):
        if test_packages_name in module_name:
            del sys.modules[module_name]
            print(f"deleted {module_name}")

if not isinstance(sys.stdout, MayaStdOutWrapper):
    sys.stdout = MayaStdOutWrapper(sys.stdout)

reload_tests("テストパッケージ名")

pytest.main(["-v", "実行したいテストフォルダ"])

後は、pytestを実行したいテストフォルダ以下に「conftest.py」というファイル名で
関数ごとにMayaシーンを新規で開くフックを書いて置くとテストがしやすい。
公式

conftest.py
import pytest
from maya import cmds

@pytest.fixture(autouse=True)
def setup():
    print("テスト関数実行前")
    cmds.file(newFile=True, force=True)
    yield
    print("テスト関数実行後")

Discussion