#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.