oTree Forum >

When is app_after_this_page called?

#1 by ccrabbe

Hi all -

I am  in a situation where I am trying to use app_after_this_page to kick out subjects who time out on a decision page in my experiment.

My plan was to set a participant.vars flag in before_next page if timeout_happened=True, then check this flag in app_after_this_page, and if true to return the name of a dropout catcher app later in my app_sequence.

However, it seems like app_after_this_page isn't executed when timeout_happened==True for some reason?  Here's the print trace of my execution with 4 subjects, with the last one timing out:

Guess.before_next_page called for player:  178
Guess.app_after_this_page called for player:  178
player.participant.vars= {'randomly_paid_task': 'g2_r8', 'role': 'col', 'previous_partner': 179, 'chosen_for_bonus': False, 'wait_page_arrival_1': 1719528280.0934074}

Guess.before_next_page called for player:  179
Guess.app_after_this_page called for player:  179
player.participant.vars= {'randomly_paid_task': 'g1_q2_r2', 'role': 'row', 'previous_partner': 178, 'chosen_for_bonus': False, 'wait_page_arrival_1': 1719528280.2678099}

Guess.before_next_page called for player:  180
Guess.app_after_this_page called for player:  180
player.participant.vars= {'randomly_paid_task': 'g2_r2', 'role': 'row', 'previous_partner': 181, 'chosen_for_bonus': True, 'wait_page_arrival_1': 1719528281.133287}

Guess.before_next_page called for player:  181
player  181  Guess timeout
participant.vars= {'randomly_paid_task': 'g2b_r1', 'role': 'col', 'previous_partner': 180, 'chosen_for_bonus': False, 'wait_page_arrival_1': 1719528281.217235, 'dropped_out.r1': True}

The "Guess timeout" is called inside before_next_page only if timeout_happened is true.  It doesn't appear to execute app_after_this_page if timeout_happened is true.

If this is the case, does anybody have a good idea how I can skip to a later app upon soemeone timing out?

Thanks,
--Chris

#2 by BonnEconLab

Can’t you simply introduce an intermediate pseudo page that follows your Guess page?

That is, on Guess, use before_next_page to set your participant.vars dropout flag, and then on PseudoPage, check that flag in app_after_this_page?

#3 by ccrabbe

Thanks for the workaround idea.  I still can't think of the benefit of having app_after_this_page not called if timeout_happneed, but I'm sure there's a good reason.

Since I am attempting to detect dropouts on many pages, instead of doubling the length of my page_sequence it feels simpler/cleaner to have one pseudopage at the end of my page_sequence which is displayed only to people with the dropped_out flag.  It's auto-submitted by javascript, and its app_after_this_page is what kicks subjects to the end of the app_sequence.

Thanks again,
--Chris

#4 by BonnEconLab (edited )

I just tried to reproduce your issue in a minimal working example. However, I was unable to reproduce the behavior that you described:

> My plan was to set a participant.vars flag in before_next page if timeout_happened=True, then check this flag in app_after_this_page, and if true to return the name of a dropout catcher app later in my app_sequence.
>
> However, it seems like app_after_this_page isn't executed when timeout_happened==True for some reason?

In other words, your approach works flawlessly in my MWE:


class MyPage(Page):

    timeout_seconds = 10

    @staticmethod
    def vars_for_template(player):
        player.participant.dropped_out = False

    @staticmethod
    def before_next_page(player, timeout_happened):
        if timeout_happened:
            player.participant.dropped_out = True

    @staticmethod
    def app_after_this_page(player, upcoming_apps):
        if player.participant.dropped_out == True:
            return "zzz_dropout_app_end"


In the settings.py file, I set:


SESSION_CONFIGS = [
    dict(
        display_name = "Flag dropouts and move them to other app (https://www.otreehub.com/forum/1146/)",
        name = "zzz_dropout_app",
        app_sequence = ["zzz_dropout_app", "zzz_dropout_app_end"],
        num_demo_participants = 4,
    ),
]

and

PARTICIPANT_FIELDS = [
    "dropped_out",
]


(I used oTree 5.10.4 for my testing.)

Write a reply

Set forum username