oTree Forum >

Floats appearing as BinaryExpression

#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

Write a reply

Set forum username