oTree Forum >

Market Entry otree Experiment Issues

#1 by caroolin

Hello!
I have an issue with my __init_. I created the following for a Market Entry game:

from otree.api import Currency, models, BaseConstants, BaseSubsession, BaseGroup, BasePlayer
from otree.api import Page, WaitPage

doc = """
Market Entry Game
"""


class C(BaseConstants):
    NAME_IN_URL = 'market_game'
    PLAYERS_PER_GROUP = 2
    NUM_ROUNDS = 6


class Subsession(BaseSubsession):
    market_condition = models.StringField()

    def creating_session(self):
        condition_sequence = ['Favorable', 'Unfavorable', 'Moderate']
        round_index = (self.round_number - 1) % 3
        self.market_condition = condition_sequence[round_index]


class Group(BaseGroup):
    def set_payoffs(self):
        for p in self.get_players():
            p.set_payoff()


class Player(BasePlayer):
    decision = models.StringField(choices=['Enter', 'Hold'])

    def set_payoff(self):
        other_player = self.get_others_in_group()[0]
        condition = self.subsession.market_condition
        decision = self.decision
        other_decision = other_player.decision

        if condition == 'Favorable':
            if decision == 'Enter' and other_decision == 'Hold':
                self.payoff = Currency(100)
                other_player.payoff = Currency(10)
            elif decision == 'Hold' and other_decision == 'Enter':
                self.payoff = Currency(10)
                other_player.payoff = Currency(100)
            elif decision == 'Enter' and other_decision == 'Enter':
                self.payoff = Currency(50)
                other_player.payoff = Currency(50)
            elif decision == 'Hold' and other_decision == 'Hold':
                self.payoff = Currency(10)
                other_player.payoff = Currency(10)
        elif condition == 'Unfavorable':
            if decision == 'Enter' and other_decision == 'Hold':
                self.payoff = Currency(-5)
                other_player.payoff = Currency(10)
            elif decision == 'Hold' and other_decision == 'Enter':
                self.payoff = Currency(10)
                other_player.payoff = Currency(-5)
            elif decision == 'Enter' and other_decision == 'Enter':
                self.payoff = Currency(-10)
                other_player.payoff = Currency(-10)
            elif decision == 'Hold' and other_decision == 'Hold':
                self.payoff = Currency(10)
                other_player.payoff = Currency(10)
        elif condition == 'Moderate':
            if decision == 'Enter' and other_decision == 'Hold':
                self.payoff = Currency(40)
                other_player.payoff = Currency(10)
            elif decision == 'Hold' and other_decision == 'Enter':
                self.payoff = Currency(10)
                other_player.payoff = Currency(40)
            elif decision == 'Enter' and other_decision == 'Enter':
                self.payoff = Currency(20)
                other_player.payoff = Currency(20)
            elif decision == 'Hold' and other_decision == 'Hold':
                self.payoff = Currency(10)
                other_player.payoff = Currency(10)


# PAGES
class MarketConditionPage(Page):
    def vars_for_template(self):
        return {'market_condition': self.subsession.market_condition}


class DecisionPage(Page):
    form_model = 'player'
    form_fields = ['decision']


class ResultsWaitPage(WaitPage):
    after_all_players_arrive = 'set_payoffs'


class Results(Page):
      def vars_for_template(self):
        return {
            'my_decision': self.player.decision,
            'other_player_decision': self.player.get_others_in_group()[0].decision,
            'my_payoff': self.player.payoff,
            'other_player_payoff': self.player.get_others_in_group()[0].payoff,
            'market_condition': self.subsession.market_condition
        }


page_sequence = [MarketConditionPage, DecisionPage, ResultsWaitPage, Results]

I receive the following errors:
Unresolved attribute reference 'subsession' for class 'MarketConditionPage'
Unresolved attribute reference 'player' for class 'Results'
Unresolved attribute reference 'subsession' for class 'Results'

#2 by fabsi

Hi caroolin,

Please try to adjust your implementation of the vars_for_template method to:

class MarketConditionPage(Page):
    @staticmethod
    def vars_for_template(player):
        return {'market_condition': player.subsession.market_condition}
        
class Results(Page):
    @staticmethod
    def vars_for_template(player):
        return {
            'my_decision': player.decision,
            'other_player_decision': player.get_others_in_group()[0].decision,
            'my_payoff': player.payoff,
            'other_player_payoff': player.get_others_in_group()[0].payoff,
            'market_condition': player.subsession.market_condition
        }
        
In your current implementation, vars_for_template is an instance method because it lacks the @staticmethod decorator. Instance methods always take at least one parameter, self, which points to an instance of the class when the method is called, e.g., an instance of the MarketConditionPage class. 
However, the instance of the class does not have the attributes subsection, player, or subsession, hence the errors.

vars_for_template should be a static method that takes one parameter, namely the player object.

Check out the documentation here: https://otree.readthedocs.io/en/latest/pages.html?highlight=vars_for_template#vars-for-template

#3 by caroolin

Hello!

Thank you for the reply @fabsi!
I adapted my code accordingly:
from otree.api import Currency, models, BaseConstants, BaseSubsession, BaseGroup, BasePlayer
from otree.api import Page, WaitPage

doc = """
Market Entry Game
"""


class C(BaseConstants):
    NAME_IN_URL = 'market_game'
    PLAYERS_PER_GROUP = 2
    NUM_ROUNDS = 6


class Subsession(BaseSubsession):
    market_condition = models.StringField()

    def creating_session(self):
        print("creating_session is being called")  # Debug print
        condition_sequence = ['Favorable', 'Unfavorable', 'Moderate']
        round_index = (self.round_number - 1) % 3
        self.market_condition = condition_sequence[round_index]
        print("Market condition set to:", self.market_condition)


class Group(BaseGroup):
    def set_payoffs(self):
        for p in self.get_players():
            p.set_payoff()


class Player(BasePlayer):
    decision = models.StringField(choices=['Enter', 'Hold'])

    def set_payoff(self):
        other_player = self.get_others_in_group()[0]
        condition = self.subsession.market_condition
        decision = self.decision
        other_decision = other_player.decision

        if condition == 'Favorable':
            if decision == 'Enter' and other_decision == 'Hold':
                self.payoff = Currency(100)
                other_player.payoff = Currency(10)
            elif decision == 'Hold' and other_decision == 'Enter':
                self.payoff = Currency(10)
                other_player.payoff = Currency(100)
            elif decision == 'Enter' and other_decision == 'Enter':
                self.payoff = Currency(50)
                other_player.payoff = Currency(50)
            elif decision == 'Hold' and other_decision == 'Hold':
                self.payoff = Currency(10)
                other_player.payoff = Currency(10)
        elif condition == 'Unfavorable':
            if decision == 'Enter' and other_decision == 'Hold':
                self.payoff = Currency(-5)
                other_player.payoff = Currency(10)
            elif decision == 'Hold' and other_decision == 'Enter':
                self.payoff = Currency(10)
                other_player.payoff = Currency(-5)
            elif decision == 'Enter' and other_decision == 'Enter':
                self.payoff = Currency(-10)
                other_player.payoff = Currency(-10)
            elif decision == 'Hold' and other_decision == 'Hold':
                self.payoff = Currency(10)
                other_player.payoff = Currency(10)
        elif condition == 'Moderate':
            if decision == 'Enter' and other_decision == 'Hold':
                self.payoff = Currency(40)
                other_player.payoff = Currency(10)
            elif decision == 'Hold' and other_decision == 'Enter':
                self.payoff = Currency(10)
                other_player.payoff = Currency(40)
            elif decision == 'Enter' and other_decision == 'Enter':
                self.payoff = Currency(20)
                other_player.payoff = Currency(20)
            elif decision == 'Hold' and other_decision == 'Hold':
                self.payoff = Currency(10)
                other_player.payoff = Currency(10)


# PAGES
class MarketConditionPage(Page):
    @staticmethod
    def vars_for_template(player):
        return {'market_condition': player.subsession.market_condition}


class DecisionPage(Page):
    form_model = 'player'
    form_fields = ['decision']


class ResultsWaitPage(WaitPage):
    after_all_players_arrive = 'set_payoffs'


class Results(Page):
    @staticmethod
    def vars_for_template(player):
        return {
            'my_decision': player.decision,
            'other_player_decision': player.get_others_in_group()[0].decision,
            'my_payoff': player.payoff,
            'other_player_payoff': player.get_others_in_group()[0].payoff,
            'market_condition': player.subsession.market_condition
        }


page_sequence = [MarketConditionPage, DecisionPage, ResultsWaitPage, Results]


However, when I start the otree devserver, I receive:
TypeError: subsession.market_condition is None. Accessing a null field is generally considered an error. Or, if this is intentional, use field_maybe_none()

#4 by Victor (edited )

Hey! Are you using the most recent version of oTree? I think so because you said this is your __init__.py. This typically puts the typical functions together, just before "# PAGES." See here: https://otree.readthedocs.io/zh-cn/latest/misc/noself.html?highlight=functions

Are you sure "def creating_session(self)" runs at the start? And these other functions? I think you might want to move it. Just a guess. 

Best,

Victor

PS: You also do not have to use "self"

#5 by Fanist

I agree with Victor that you should put creating_session() out of Subession Class, just put it as a standalone function in .py.

Write a reply

Set forum username