1
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 3 years have passed since last update.

xontribを作る上で引っかかったポイント

Posted at

まず

xonshと言ったらばんくしさんのブログを見ましょう。これを見れば大体できます。

目次

  1. cookiecutter-xontribが使えない!
  2. 関数を別モジュールに切り出したい
  3. -eとgitでモジュールが読めなくなる話
  4. テストを書きたい話

cookiecutter-xontribが使えない!

xontribの雛形を作るのに便利ですが、 https://github.com/laerus/cookiecutter-xontrib がなくなってしまっています。

xonsh公式が出しているのでそちらをそのまま使いましょう。 https://github.com/xonsh/xontrib-cookiecutter
作成直後の構造↓

.
├── LICENSE
├── README.rst
├── setup.cfg
├── setup.py
└── xontrib
    └── sample.xsh

ちなみに、公式版では新しく setup.cfg が追加されていますが、今までsetup関数に与えていた引数を別出ししているだけなので特に変わりなく使えます。

関数を別モジュールに切り出したい

公式のチュートリアルにもあるように、libモジュールを作成して読み込みたい時

xontrib/
 |- javert.xsh     # "javert", because in xontrib
 |- your.py        # "your",
 |- eyes/
    |- __init__.py
    |- scream.xsh  # "eyes.scream", because eyes is in xontrib
[javert.xsh]

from .eyes import scream # ○
from eyes import scream  # ×

xontribよりpython全般の話になってきますが、相対読み込みを使わないとこけます。半日溶かしました

xpip install -e と pip install git+ で動きが違う(動かなくなる)話

前者は動き、後者は動かなく(module not found)なりました。

結論としては、setupの書き方に問題がありました。

...
package_data = {'xontrib': [ここ]},
...

xontribの先人の方々は *.xsh と書いていたため、「この部分にパッケージに含めるファイルを記述する」と推測して ./**/*.py と記述すると動きます。

これも半日溶かしました。

テストを書きたい

こちらの記事(すごい!)を参考にして全てpyに置き換えている前提です。

普通にunittestを走らせると、 builtins.__xonsh__.env を呼んでいるタイミングで落ちると思います。xonshがないので当然といえば当然です。
なので、mockを使います。

import unittest
from unittest.mock import patch, MagicMock

# 別ファイルにすると見栄えがいい
sample_xonsh = {
    "env": {
		# モックにしておきたい環境変数を作る
    },
    "execer": MagicMock()
}
mock_xonsh = MagicMock()
mock_xonsh.__getitem__.side_effect = sample_xonsh.__getitem__
mock_aliases = MagicMock()
# -------------------------

class TestSample(unittest.TestCase):
    def setUp(self):
        self.patcher_xonsh = patch('builtins.__xonsh__', new=mock_xonsh, create=True)
        self.patcher_aliases = patch('builtins.aliases', new=mock_aliases, create=True)
        self.mock_xonsh = self.patcher_xonsh.start()
        self.mock_aliases = self.patcher_aliases.start()
    
    def tearDown(self):
        self.patcher_xonsh.stop()
        self.patcher_aliases.stop()
    
    def test_sample(self):
        from xontrib.hellolib import hello
        # テストを行う

if __name__ == "__main__":
    unittest.main()

ポイントは

  • create=True でパッチを作成すること(上書きではないので)
  • xontribのインポートは各テスト関数内で行うこと(patchより先にインポートしてしまうとモック化の意味がない(エラー))
  • execerにMagicMockを代入しておくこと(execer.evalは関数なので引数を後から見れた方が良い感じ)

xontribのテストはモックの量がめちゃめちゃに多くなりそうで悲しくなっています。
また詰まったときは追記していきます。

1
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?