Bots: 高级特性¶
这些高级特性大多数在oTree Studio中不被支持。
命令行bots¶
一种可选的在浏览器中运行bots的方式是在命令行中运行。命令行bots运行更快且需要更少的安装步骤。
运行下面的代码:
otree test mysession
使用指定参与者人数进行测试(否则默认为 num_demo_participants
):
otree test mysession 6
在所有session config上运行测试:
otree test
导出数据¶
使用 --export
选项来将结果导出为CSV文件:
otree test mysession --export
为指定数据所保存的文件夹,可使用:
otree test mysession --export=myfolder
命令行浏览器bots¶
你可以在命令行启动bots,通过使用 otree browser_bots
。
确保已安装了Google Chrome,或在
settings.py
中设置了BROWSER_COMMAND
(更多信息见下面)设置
OTREE_REST_KEY
环境变量如 REST 中所述。运行你的服务器
关闭所有Chrome窗口。
运行下面的代码:
otree browser_bots mysession
这会启动数个Chrome标签页并运行bots。当完成后,标签页会自动关闭,并且你会在终端窗口中看到一份报告。
如果Chrome没有正常关闭窗口,确保你在运行指令之前已经关闭了所有Chrome窗口。
远程服务器(例如 Heroku)上的命令行bots¶
如果服务器不是运行在通常的主机/端口 http://localhost:8000
上,你需要传递 --server-url
参数。例如,如果在Heroku上,你需要这样做:
otree browser_bots mysession --server-url=https://YOUR-SITE.herokuapp.com
选择session config与人数¶
你可以指定参与人的人数:
otree browser_bots mysession 6
为测试所有的session config,运行:
otree browser_bots
浏览器bots:杂项¶
你可以使用非Chrome浏览器,需在 settings.py
中设置 BROWSER_COMMAND
。然后,oTree会自动启动浏览器,通过类似 subprocess.Popen(settings.BROWSER_COMMAND)
的操作。
测试用例¶
你可以在你的PlayerBot类中定义属性 cases
来列出不同的测试用例。例如,在公共品博弈中,你可能想要测试三种场景:
- 所有玩家贡献其初始值的一半
- 所有玩家均不做任何贡献
- 所有玩家贡献出他们全部的初始值(100点)
你可以分别将3个测试用例命名为”basic”,”min” 和 “max”,并将他们放在 cases
中。然后,oTree会自动执行bot3次,每次一个测试用例。每一次执行时, cases
中的不同值都会在bot中被赋值给 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
注解
如果你使用测试用例,更推荐使用 命令行bots 因为浏览器bots仅会执行一个单独的用例。
cases
必须是列表,但可以包含任何数据类型,如字符串,整数,甚至字典。下面是一个信任博弈,它使用字典作为用例。
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,
)
)
Bot系统不会告诉我们具体 为什么 提交会失败,这是缺失的信息。是 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__']
。
杂项¶
在bots中,赋值语句 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.money_left
是安全的,因为 self.player
会从数据库中获取最新的数据。
实时页面¶
为使用机器人测试实时方法,在 tests.py
中定义顶级函数 call_live_method
。(在oTree Studio中不可用。)此函数可模拟一系列对你的 live_method
的调用。参数 method
模拟你的玩家模型中的实时方法。例如, method(3, 'hello')
调用了玩家3上的实时方法,并且 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
当小组中最快的bot到达一个有 live_method
的页面时 call_live_method
会被自动执行。(其他bot此时可能在前一个页面,除非你使用等待页面限制了这种情况。)