Repeating an app in app_sequence

541 views
Skip to first unread message

razva...@gmail.com

unread,
Mar 19, 2021, 9:04:36 AM3/19/21
to oTree help & discussion
Hi,

I would like participants to play an app twice (the app already has x rounds within it). It would be much easier for me to run the same app twice instead of having 2x rounds within the same app. Is there any way to do this? 

Thanks,
Razvan

Chris @ oTree

unread,
Mar 19, 2021, 11:17:51 AM3/19/21
to oTree help & discussion
If you're using the new "no-self" format, this shouldn't be too hard.

Let's call the first app appcopy1. In this app, make sure each page has template_name set explicitly:

class MyPage(Page):
  template_name = 'appcopy1/MyPage.html'


Then, appcopy2 can just import everything from appcopy1. However, you need to copy/paste the Player/Group/Subsession class and any fields from the first app. Also you need a different name_in_url. That means your __init__.py can just be this:

from appcopy1 import *


class Constants(Constants):
  name_in_url = 'appcopy2'

class Subsession(BaseSubsession):
  pass

class Group(BaseGroup):
  pass

class Player(BasePlayer):
  xyz = models.IntegerField()

And that's it. You don't need any templates in this app, so it will just be an __init__.py with the above content and nothing else.

I haven't tested it thoroughly but in principle it should work.

razva...@gmail.com

unread,
Mar 19, 2021, 1:06:04 PM3/19/21
to oTree help & discussion
Thanks a lot! 

BonnEconLab

unread,
Aug 12, 2021, 8:58:48 AM8/12/21
to oTree help & discussion
Here’s a simpler solution that requires no copy-and-paste whatsoever. I have tested it in Linux, macOS, and Windows:
  1. Create a symbolic link to the folder appcopy1. Let’s give this symbolic link the name appcopy2.
    In Linux and macOS, the Terminal command for doing so is ln -s appcopy1 appcopy2.
    In Windows, you need to run the Command Line as an administrator and execute mklink /D appcopy2 appcopy1.
  2. As Chris mentioned, we need to make sure that name_in_url is unique per app. A way to do so is generating it as a sufficiently (say, 20 characters) long random string: in the file __init__.py, include import random and then set name_in_url = ''.join(random.SystemRandom().choice(string.ascii_uppercase + string.digits) for _ in range(20)).
    Alternatively/additionally, in order to ensure uniqueness, you can also incorporate the current time including milliseconds in name_in_url: include from datetime import datetime in the __init__.py file and set name_in_url = "WhateverYouLike" + datetime.now().strftime("%Y%m%dT%H%M%S%f").

BonnEconLab

unread,
Aug 12, 2021, 9:32:05 AM8/12/21
to oTree help & discussion
PS: If you use oTree’s “models.py” format instead of the “no-self” format, you can do something similar but more pedestrian:
  1. In the oTree project folder, create a new folder appcopy2.
  2. In appcopy2, create symbolic links to all files and subfolders that you need from the appcopy1 folder, except for the templates subfolder (and of course, except for the __pycache__, _builtin, and migrations subfolders). Give the symbolic link the same name as the original file.
     (For instance, in macOS, from within appcopy2, execute ln -s ../appcopy1/models.py models.py, etc.)
  3. In appcopy2, Create a templates subfolder.
  4. In appcopy2/templates, create a symbolic link of the name appcopy2 to appcopy1/templates/appcopy1.
    (For instance, in macOS, from within appcopy2/templates, execute ln -s ../../appcopy1/templates/appcopy1 appcopy2.)
  5. Importantly, also with this solution, you need to make sure that name_in_url is unique across apps.
    For instance, you can set name_in_url = ''.join(random.SystemRandom().choice(string.ascii_uppercase + string.digits) for _ in range(20)) in models.py (and include the line import random).
Cheers,

Holger

Chris @ oTree

unread,
Aug 12, 2021, 12:27:47 PM8/12/21
to oTree help & discussion
Clever!
Reply all
Reply to author
Forward
0 new messages