ボット: 高度な機能¶
これらの機能の多くはは oTree スタジオにおいて、サポートされていません。
コマンドラインボット¶
Webブラウザーでボットを実行する代わりに、コマンドラインでボットを実行することもできます。コマンドラインボットはより高速に実行され、セットアップも少なくて済みます。
これを実行します。
otree test mysession
特定の数の参加者でテストするには(それ以外の場合はデフォルトで num_demo_participants
):
otree test mysession 6
すべてのセッション構成のテストを実行するには:
otree test
データのエクスポート¶
--export
フラグを使用して、結果をCSVファイルにエクスポートします。
otree test mysession --export
データが保存されるフォルダを指定するには、次の手順を実行します。
otree test mysession --export=myfolder
コマンドラインブラウザボット¶
otree browser_bots
を使用して、コマンドラインからブラウザボットを起動できます。
Google Chromeがインストールされていることを確認するか、
BROWSER_COMMAND
をsettings.py
で設定してください。(下記詳細)。REST の説明に従って、環境変数
OTREE_REST_KEY
を設定します。サーバを実行する。
すべてのChromeウィンドウを閉じます。
これを実行します。
otree browser_bots mysession
これにより、いくつかのChromeタブが起動し、ボットが実行されます。終了すると、タブが閉じ、ターミナルにレポートが表示されます。
Chromeでウィンドウが正しく閉じられない場合は、コマンドを起動する前に、必ずすべてのChromeウィンドウを閉じてください。
リモートサーバー(Herokuなど)上のコマンドラインブラウザボット¶
サーバーが通常の http://localhost:8000
以外のホスト/ポートで実行されている場合は、 --server-url
を渡す必要があります。例えば、Herokuにある場合は、次のようにします。
otree browser_bots mysession --server-url=https://YOUR-SITE.herokuapp.com
セッションの構成とサイズの選択¶
参加者の数を指定できます。
otree browser_bots mysession 6
次のコマンドを実行することですべてのセッション構成をテストすることができます。
otree browser_bots
ブラウザボット: その他の注意¶
settings.py
で BROWSER_COMMAND
を設定することで 、Chrome以外のブラウザを使用できます。そして、oTreeは subprocess.Popen(settings.BROWSER_COMMAND)
のようなコマンドを実行してブラウザを開きます。
テストケース¶
さまざまなテストケースのリストである、属性 cases
をPlayerBotクラスに定義できます。たとえば、公共財ゲームでは、次の3つのシナリオをテストすることができます。
- すべてのプレイヤーが財産の半分を寄付するケース
- すべてのプレイヤーが何も寄付しないケース
- すべてのプレイヤーが全財産(100ポイント)を寄付するケース
これらの3つのテストケースをそれぞれ "basic" 、 "min" 、 "max" と呼び、 cases
に格納します。次に、oTreeは各テストケースに対して1回ずつ、計3回ボットを実行します。毎回 、 cases
から様々な値がボットの self.case
に割り当てられます。
例:
class PlayerBot(Bot):
cases = ['basic', 'min', 'max']
def play_round(self):
yield (pages.Introduction)
if self.case == 'basic':
assert self.player.payoff == None
if self.case == 'basic':
if self.player.id_in_group == 1:
for invalid_contribution in [-1, 101]:
yield SubmissionMustFail(pages.Contribute, {'contribution': invalid_contribution})
contribution = {
'min': 0,
'max': 100,
'basic': 50,
}[self.case]
yield (pages.Contribute, {"contribution": contribution})
yield (pages.Results)
if self.player.id_in_group == 1:
if self.case == 'min':
expected_payoff = 110
elif self.case == 'max':
expected_payoff = 190
else:
expected_payoff = 150
assert self.player.payoff == expected_payoff
注釈
ユースケースを使用する場合、ブラウザボットは単一のケースしか実行しないため、 コマンドラインボット を使用することをおすすめします。
cases
はリストである必要がありますが、文字列、整数、さらには辞書など、任意のデータ型を格納することができます。下記のコードは、辞書をケースとして使用する、 trust ゲームのためのボットです。
class PlayerBot(Bot):
cases = [
{'offer': 0, 'return': 0, 'p1_payoff': 10, 'p2_payoff': 0},
{'offer': 5, 'return': 10, 'p1_payoff': 15, 'p2_payoff': 5},
{'offer': 10, 'return': 30, 'p1_payoff': 30, 'p2_payoff': 0}
]
def play_round(self):
case = self.case
if self.player.id_in_group == 1:
yield (pages.Send, {"sent_amount": case['offer']})
else:
for invalid_return in [-1, case['offer'] * C.MULTIPLICATION_FACTOR + 1]:
yield SubmissionMustFail(pages.SendBack, {'sent_back_amount': invalid_return})
yield (pages.SendBack, {'sent_back_amount': case['return']})
yield (pages.Results)
if self.player.id_in_group == 1:
expected_payoff = case['p1_payoff']
else:
expected_payoff = case['p2_payoff']
assert self.player.payoff == expected_payoff
error_fields¶
複数のフィールドを持つフォームで SubmissionMustFail
を使用する場合は、 error_fields
を使用することができます。
例えば、 age
で有効な送信がなされ、 weight
や height
が無効な送信であったとします。
yield SubmissionMustFail(
pages.Survey,
dict(
age=20,
weight=-1,
height=-1,
)
)
ボットシステムは送信が失敗する理由を正確に教えてくれません。weight
と height
のどちらが無効なのか、またはその両方が無効であるのか、 error_fields
はそのあいまいさを解決できます:
yield SubmissionMustFail(
pages.Survey,
dict(
age=20,
weight=-1,
height=-1,
),
error_fields=['weight', 'height']
)
これにより`` weight`` と height
にエラーが含まれていることが確認されますが、 age
は含まれていません。
error_message がエラーを返す場合、 error_fields
は ['__all__']
になります。
その他の注意¶
ボットでは、その種のコードが他の場所で推奨されている場合でも、player = self.player
(または、 participant = self.participant
等)を割り当てるのは危険です
yield
の間にある場合、データが古くなる可能性があるためです。
player = self.player
expect(player.money_left, cu(10))
yield pages.Contribute, dict(contribution=cu(1))
# don't do this!
# "player" variable still has the data from BEFORE pages.Contribute was submitted.
expect(player.money_left, cu(9))
実行中の self.player
がデータベースから最新のデータを取得するため、 self.player.money_left
を直接使用する方が安全です。
ライブページ¶
ボットでライブページをテストするために、 tests.py
で最上位関数として call_live_method
を定義します。(oTree Studioでは使用できません。)この関数は live_method
への呼び出しシーケンスをシミュレートします。引数 method
は、Playerクラスのライブメソッドをシミュレートします。例えば、 method(3, 'hello')
プレイヤー3のliveメソッドを呼び出し、data
に 'hello'
を設定します。例:
def call_live_method(method, **kwargs):
method(1, {"offer": 50})
method(2, {"accepted": False})
method(1, {"offer": 60})
retval = method(2, {"accepted": True})
# you can do asserts on retval
kwargs
には少なくとも以下のパラメータが含まれます。
case
テストケース を参照。page_class
: 現在のページクラス。例えば、pages.MyPage
round_number
call_live_method
はグループ内で最速のボットが live_method
を持つページに遷移すると自動的に実行されます。(WaitPage でこれを制限しない限り、他のボットはその時点で前のページにある可能性があります。)