#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