#1 by jamie
Hi there,
I have a number of variables set as models.FloatField in my Player and Group class which when I run my code are being returned as BinaryExpressions giving me the following error:
File "c:\users\mclja\appdata\local\programs\python\python39\lib\site-packages\otree\database.py", line 551, in __setattr__
raise TypeError(msg)
TypeError: balance should be set to float, not BinaryExpression.
Any help would be greatly appreciated.
#2
by
ccrabbe
Hi Jamie - Could you look through the stacktrace of your error for the line of code inside your app which generates that error (probably __init__.py), and then paste us that section of your code so that we can see what you're trying to do? Thanks, --Chris
#3 by jamie
Hi Chris,
The stacktrace is here:
Exception in ASGI application
Traceback (most recent call last):
File "c:\users\mclja\appdata\local\programs\python\python39\lib\site-packages\uvicorn\protocols\websockets\websockets_impl.py", line 162, in run_asgi
result = await self.app(self.scope, self.asgi_receive, self.asgi_send)
File "c:\users\mclja\appdata\local\programs\python\python39\lib\site-packages\uvicorn\middleware\proxy_headers.py", line 45, in __call__
return await self.app(scope, receive, send)
File "c:\users\mclja\appdata\local\programs\python\python39\lib\site-packages\starlette\applications.py", line 112, in __call__
await self.middleware_stack(scope, receive, send)
File "c:\users\mclja\appdata\local\programs\python\python39\lib\site-packages\starlette\middleware\base.py", line 21, in __call__
await self.app(scope, receive, send)
File "c:\users\mclja\appdata\local\programs\python\python39\lib\site-packages\otree\errorpage.py", line 214, in __call__
await self.app(scope, receive, send)
File "c:\users\mclja\appdata\local\programs\python\python39\lib\site-packages\starlette\middleware\base.py", line 21, in __call__
await self.app(scope, receive, send)
File "c:\users\mclja\appdata\local\programs\python\python39\lib\site-packages\starlette\middleware\sessions.py", line 75, in __call__
await self.app(scope, receive, send_wrapper)
File "c:\users\mclja\appdata\local\programs\python\python39\lib\site-packages\otree\patch.py", line 16, in __call__
await self.app(scope, receive, send)
File "c:\users\mclja\appdata\local\programs\python\python39\lib\site-packages\starlette\routing.py", line 582, in __call__
await route.handle(scope, receive, send)
File "c:\users\mclja\appdata\local\programs\python\python39\lib\site-packages\starlette\routing.py", line 299, in handle
await self.app(scope, receive, send)
File "c:\users\mclja\appdata\local\programs\python\python39\lib\site-packages\starlette\endpoints.py", line 74, in dispatch
raise exc from None
File "c:\users\mclja\appdata\local\programs\python\python39\lib\site-packages\starlette\endpoints.py", line 68, in dispatch
await self.on_receive(websocket, data)
File "c:\users\mclja\appdata\local\programs\python\python39\lib\site-packages\otree\channels\consumers.py", line 127, in on_receive
await self.post_receive_json(data, **self.cleaned_kwargs)
File "c:\users\mclja\appdata\local\programs\python\python39\lib\site-packages\otree\channels\consumers.py", line 194, in post_receive_json
await live_payload_function(
File "c:\users\mclja\appdata\local\programs\python\python39\lib\site-packages\otree\live.py", line 45, in live_payload_function
retval = call_live_method_compat(live_method, player, payload)
File "c:\users\mclja\appdata\local\programs\python\python39\lib\site-packages\otree\live.py", line 101, in call_live_method_compat
return live_method(player, payload)
File "C:\Users\mclja\PycharmProjects\thesisprogram\singleauction\singleauction\__init__.py", line 289, in live_method
buy_one(player)
File "C:\Users\mclja\PycharmProjects\thesisprogram\singleauction\singleauction\__init__.py", line 187, in buy_one
p.balance -= Group.buy_price
File "c:\users\mclja\appdata\local\programs\python\python39\lib\site-packages\otree\database.py", line 551, in __setattr__
raise TypeError(msg)
TypeError: balance should be set to float, not BinaryExpression.
The section of code which is raising the error is part of a livemethod:
class TradingForecasting(Page):
@staticmethod
def live_method(player: Player, data):
if data == "buy":
player.trade_type = 'buy'
if data == "sell":
player.trade_type = 'buy'
if player.trade_type == 'sell':
if player.num_shares_in_possession > 0:
player.validtrade = True
else:
if player.balance >= 100:
player.validtrade = True
else:
player.validtrade = False
if player.trade_type == 'buy':
if (player.balance - Group.buy_price) > 0:
player.validtrade = True
else:
Player.validtrade = False
if player.is_trader:
if data["trade_type"] == "buy":
buy_one(player)
return {
p.id_in_group: dict(
buy_price=Group.buy_price,
sell_price=Group.sell_price,
current_price=Group.current_price,
num_shares_in_possession=p.num_shares_in_possession,
escrow_amount=p.escrow_amount,
balance=p.balance
) for p in player.group.get_players()
}
if data["trade_type"] == "sell":
sell_one(player)
return {
p.id_in_group: dict(
buy_price=Group.buy_price,
sell_price=Group.sell_price,
current_price=Group.current_price,
num_shares_in_possession=p.num_shares_in_possession,
escrow_amount=p.escrow_amount,
balance=p.balance
) for p in player.group.get_players()
}
Which calls these functions:
def buy_one(p: Player):
p.trade_type = 'buy'
if p.validtrade:
p.balance -= Group.buy_price
p.num_shares_in_possession = p.num_shares_in_possession + 1
Group.mm_curr_balance += Group.buy_price
Group.mm_asset_balance -= 1
buy_cost()
sell_cost()
current_price()
else:
invalid_trade(p)
def buy_cost():
Group.buy_price = (C.K / (Group.mm_asset_balance - 1) * (Group.mm_asset_balance - 1))
The live page initialises correctly but then gives this error once the 'buy' button is clicked by the participant.
Thanks
Jamie
#4
by
ccrabbe
Hi Jamie - So the line of code is: p.balance -= Group.buy_price What is Group.buy_price? Python seems to think it's a BinaryExpression. in oTree, capital-G Group is usually a thing which you use in your __init__.py to contain model fields, and then you don't refer to the class itself, you refer to an instance of the class (like you're using p:Player in your buy_one function arguments - p is a passed instance of a Player class. Anyway, I don't know Python well enough to know if referring to a class and not a class instance in this situation would result in this BinaryExpression error, but my hunch is that it's gotta be related to that, and even if it's not you should fix it anyway. I would suggest that you refactor your code to refer to an instance of the Group class (like p.group) instead of the Group class itself. Hopefully that will help. Thanks, --Chris