Exemplo n.º 1
0
def create_session(session_config_name,
                   *,
                   label='',
                   num_participants=None,
                   pre_create_id=None,
                   room_name=None,
                   for_mturk=False,
                   is_demo=False,
                   edited_session_config_fields=None) -> Session:

    session = None
    num_subsessions = 0
    edited_session_config_fields = edited_session_config_fields or {}

    try:
        session_config = SESSION_CONFIGS_DICT[session_config_name]
    except KeyError:
        msg = 'Session config "{}" not found in settings.SESSION_CONFIGS.'
        raise KeyError(msg.format(session_config_name)) from None
    else:
        # copy so that we don't mutate the original
        # .copy() returns a dict, so need to convert back to SessionConfig
        session_config = SessionConfig(session_config.copy())
        session_config.update(edited_session_config_fields)

        # check validity and converts serialized decimal & currency values
        # back to their original data type (because they were serialized
        # when passed through channels
        session_config.clean()

    with transaction.atomic():
        # 2014-5-2: i could implement this by overriding the __init__ on the
        # Session model, but I don't really know how that works, and it seems
        # to be a bit discouraged: http://goo.gl/dEXZpv
        # 2014-9-22: preassign to groups for demo mode.

        otree.db.idmap.activate_cache()

        session = Session.objects.create(
            config=session_config,
            label=label,
            _pre_create_id=pre_create_id,
            is_demo=is_demo,
            num_participants=num_participants,
        )  # type: Session

        def bulk_create(model, descriptions):
            model.objects.bulk_create([
                model(session=session, **description)
                for description in descriptions
            ])
            return model.objects.filter(session=session).order_by('pk')

        # check that it divides evenly
        session_lcm = session_config.get_lcm()
        if num_participants % session_lcm:
            msg = ('Session Config {}: Number of participants ({}) does not '
                   'divide evenly into group size ({})').format(
                       session_config['name'], num_participants, session_lcm)
            raise ValueError(msg)

        if for_mturk:
            session.mturk_num_participants = (
                num_participants / settings.MTURK_NUM_PARTICIPANTS_MULTIPLE)

        # TODO: remove start_order
        start_order = list(range(num_participants))
        if session_config.get('random_start_order'):
            random.shuffle(start_order)

        participants = bulk_create(Participant, [{
            'id_in_session': id_in_session,
            'start_order': j,
        } for id_in_session, j in enumerate(start_order, start=1)])

        ParticipantLockModel.objects.bulk_create([
            ParticipantLockModel(participant_code=participant.code)
            for participant in participants
        ])

        for app_name in session_config['app_sequence']:

            models_module = get_models_module(app_name)
            app_constants = get_app_constants(app_name)
            num_subsessions += app_constants.num_rounds

            round_numbers = list(range(1, app_constants.num_rounds + 1))

            subs = bulk_create(models_module.Subsession,
                               [{
                                   'round_number': round_number
                               } for round_number in round_numbers])

            # Create players
            models_module.Player.objects.bulk_create([
                models_module.Player(session=session,
                                     subsession=subsession,
                                     round_number=round_number,
                                     participant=participant)
                for round_number, subsession in zip(round_numbers, subs)
                for participant in participants
            ])

        session._create_groups_and_initialize()

        session.build_participant_to_player_lookups()
        # automatically save all objects since the cache was activated:
        # Player, Group, Subsession, Participant, Session
        otree.db.idmap.save_objects()
        otree.db.idmap.deactivate_cache()

        # 2017-09-27: moving this inside the transaction
        session._set_admin_report_app_names()
        session.save()
        # we don't need to mark it ready=True here...because it's in a
        # transaction

    # this should happen after session.ready = True
    if room_name is not None:
        from otree.room import ROOM_DICT
        room = ROOM_DICT[room_name]
        room.session = session

    return session
Exemplo n.º 2
0
def create_session(
        session_config_name, label='', num_participants=None,
        _pre_create_id=None,
        room_name=None, for_mturk=False, use_cli_bots=False,
        is_demo=False, force_browser_bots=False,
        honor_browser_bots_config=False, bot_case_number=None):

    session = None
    use_browser_bots = False
    num_subsessions = 0

    with transaction.atomic():
        # 2014-5-2: i could implement this by overriding the __init__ on the
        # Session model, but I don't really know how that works, and it seems
        # to be a bit discouraged: http://goo.gl/dEXZpv
        # 2014-9-22: preassign to groups for demo mode.

        otree.db.idmap.activate_cache()

        try:
            session_config = SESSION_CONFIGS_DICT[session_config_name]
        except KeyError:
            msg = 'Session config "{}" not found in settings.SESSION_CONFIGS.'
            raise ValueError(msg.format(session_config_name))

        if force_browser_bots:
            use_browser_bots = True
        elif (session_config.get('use_browser_bots') and
              honor_browser_bots_config):
            use_browser_bots = True
        else:
            use_browser_bots = False
        if use_browser_bots and bot_case_number is None:
            # choose one randomly
            num_bot_cases = session_config.get_num_bot_cases()
            # choose bot case number randomly...maybe reconsider this?
            # we can only run one.
            bot_case_number = random.choice(range(num_bot_cases))

        session = Session.objects.create(
            config=session_config,
            label=label,
            _pre_create_id=_pre_create_id,
            use_browser_bots=use_browser_bots,
            is_demo=is_demo,
            _bot_case_number=bot_case_number)

        def bulk_create(model, descriptions):
            model.objects.bulk_create([
                model(session=session, **description)
                for description in descriptions])
            return model.objects.filter(session=session).order_by('pk')

        # check that it divides evenly
        session_lcm = session_config.get_lcm()
        if num_participants % session_lcm:
            msg = (
                'Session Config {}: Number of participants ({}) does not '
                'divide evenly into group size ({})'
            ).format(session_config['name'], num_participants, session_lcm)
            raise ValueError(msg)

        if for_mturk:
            session.mturk_num_participants = (
                    num_participants /
                    settings.MTURK_NUM_PARTICIPANTS_MULTIPLE)

        start_order = list(range(num_participants))
        if session_config.get('random_start_order'):
            random.shuffle(start_order)

        participants = bulk_create(
            Participant,
            [{
                'id_in_session': id_in_session,
                'start_order': j,
                # check if id_in_session is in the bots ID list
                '_is_bot': use_cli_bots or use_browser_bots,
             }
             for id_in_session, j in enumerate(start_order, start=1)])

        ParticipantLockModel.objects.bulk_create([
            ParticipantLockModel(participant_code=participant.code)
            for participant in participants])

        try:
            for app_name in session_config['app_sequence']:

                models_module = get_models_module(app_name)
                app_constants = get_app_constants(app_name)

                num_subsessions += app_constants.num_rounds
                round_numbers = list(range(1, app_constants.num_rounds + 1))

                subs = bulk_create(
                    models_module.Subsession,
                    [{'round_number': round_number}
                     for round_number in round_numbers])

                # Create players
                models_module.Player.objects.bulk_create([
                    models_module.Player(
                        session=session,
                        subsession=subsession,
                        round_number=round_number,
                        participant=participant)
                    for round_number, subsession in zip(round_numbers, subs)
                    for participant in participants])

            session._create_groups_and_initialize()

        # session.has_bots = any(p.is_bot ...)

        # handle case where DB has missing column or table
        # missing table: OperationalError: no such table: pg_subsession
        # missing column: OperationalError: table pg_player has no column
        # named contribution2
        except OperationalError as exception:
            exception_str = str(exception)
            if 'table' in exception_str:
                ExceptionClass = type(exception)
                six.reraise(
                    ExceptionClass,
                    ExceptionClass('{} - Try resetting the database.'.format(
                        exception_str)),
                    sys.exc_info()[2])
            raise

        session.build_participant_to_player_lookups()
        # automatically save all objects since the cache was activated:
        # Player, Group, Subsession, Participant, Session
        otree.db.idmap.save_objects()
        otree.db.idmap.deactivate_cache()

    if use_browser_bots:
        # what about clear_browser_bots? if session is created through
        # UI, when do we run that? it should be run when the session
        # is deleted
        try:
            num_players_total = num_participants * num_subsessions
            otree.bots.browser.initialize_bots(
                session.code, num_players_total)
        except:
            session.delete()
            raise

    session.ready = True
    session.save()

    # this should happen after session.ready = True
    if room_name is not None:
        from otree.room import ROOM_DICT
        room = ROOM_DICT[room_name]
        room.session = session

    return session
Exemplo n.º 3
0
def create_session(session_config_name,
                   *,
                   label='',
                   num_participants=None,
                   pre_create_id=None,
                   room_name=None,
                   for_mturk=False,
                   is_demo=False,
                   edited_session_config_fields=None) -> Session:

    num_subsessions = 0
    edited_session_config_fields = edited_session_config_fields or {}

    try:
        session_config = SESSION_CONFIGS_DICT[session_config_name]
    except KeyError:
        msg = 'Session config "{}" not found in settings.SESSION_CONFIGS.'
        raise KeyError(msg.format(session_config_name)) from None
    else:
        # copy so that we don't mutate the original
        # .copy() returns a dict, so need to convert back to SessionConfig
        session_config = SessionConfig(session_config.copy())
        session_config.update(edited_session_config_fields)

        # check validity and converts serialized decimal & currency values
        # back to their original data type (because they were serialized
        # when passed through channels
        session_config.clean()

    with transaction.atomic():
        # 2014-5-2: i could implement this by overriding the __init__ on the
        # Session model, but I don't really know how that works, and it seems
        # to be a bit discouraged: http://goo.gl/dEXZpv
        # 2014-9-22: preassign to groups for demo mode.

        if for_mturk:
            mturk_num_participants = (num_participants /
                                      settings.MTURK_NUM_PARTICIPANTS_MULTIPLE)
        else:
            mturk_num_participants = -1

        session = Session.objects.create(
            config=session_config,
            label=label,
            _pre_create_id=pre_create_id,
            is_demo=is_demo,
            num_participants=num_participants,
            mturk_num_participants=mturk_num_participants)  # type: Session

        # check that it divides evenly
        session_lcm = session_config.get_lcm()
        if num_participants % session_lcm:
            msg = ('Session Config {}: Number of participants ({}) does not '
                   'divide evenly into group size ({})').format(
                       session_config['name'], num_participants, session_lcm)
            raise ValueError(msg)

        Participant.objects.bulk_create([
            Participant(id_in_session=id_in_session, session=session)
            for id_in_session in list(range(1, num_participants + 1))
        ])

        participant_values = session.participant_set.order_by('id').values(
            'code', 'id')

        ParticipantLockModel.objects.bulk_create([
            ParticipantLockModel(participant_code=participant['code'])
            for participant in participant_values
        ])

        participant_to_player_lookups = []
        page_index = 0

        for app_name in session_config['app_sequence']:

            views_module = common_internal.get_views_module(app_name)
            models_module = get_models_module(app_name)
            Constants = models_module.Constants
            num_subsessions += Constants.num_rounds

            round_numbers = list(range(1, Constants.num_rounds + 1))

            Subsession = models_module.Subsession
            Group = models_module.Group
            Player = models_module.Player

            Subsession.objects.bulk_create([
                Subsession(round_number=round_number, session=session)
                for round_number in round_numbers
            ])

            subsessions = Subsession.objects.filter(
                session=session).order_by('round_number').values(
                    'id', 'round_number')

            ppg = Constants.players_per_group
            if ppg is None or Subsession._has_group_by_arrival_time():
                ppg = num_participants

            num_groups_per_round = int(num_participants / ppg)

            groups_to_create = []
            for subsession in subsessions:
                for id_in_subsession in range(1, num_groups_per_round + 1):
                    groups_to_create.append(
                        Group(
                            session=session,
                            subsession_id=subsession['id'],
                            round_number=subsession['round_number'],
                            id_in_subsession=id_in_subsession,
                        ))

            Group.objects.bulk_create(groups_to_create)

            groups = Group.objects.filter(session=session).values(
                'id_in_subsession', 'subsession_id',
                'id').order_by('id_in_subsession')

            groups_lookup = defaultdict(list)

            for group in groups:
                subsession_id = group['subsession_id']
                groups_lookup[subsession_id].append(group['id'])

            players_to_create = []

            for subsession in subsessions:
                subsession_id = subsession['id']
                round_number = subsession['round_number']
                participant_index = 0
                for group_id in groups_lookup[subsession_id]:
                    for id_in_group in range(1, ppg + 1):
                        participant = participant_values[participant_index]
                        players_to_create.append(
                            Player(session=session,
                                   subsession_id=subsession_id,
                                   round_number=round_number,
                                   participant_id=participant['id'],
                                   group_id=group_id,
                                   id_in_group=id_in_group))
                        participant_index += 1

            # Create players
            Player.objects.bulk_create(players_to_create)

            players_flat = Player.objects.filter(session=session).values(
                'id', 'participant__code', 'participant__id', 'subsession__id',
                'round_number')

            players_by_round = [[] for _ in range(Constants.num_rounds)]
            for p in players_flat:
                players_by_round[p['round_number'] - 1].append(p)

            for round_number, round_players in enumerate(players_by_round,
                                                         start=1):
                for View in views_module.page_sequence:
                    page_index += 1
                    for p in round_players:

                        participant_code = p['participant__code']

                        url = View.get_url(participant_code=participant_code,
                                           name_in_url=Constants.name_in_url,
                                           page_index=page_index)

                        participant_to_player_lookups.append(
                            ParticipantToPlayerLookup(
                                participant_id=p['participant__id'],
                                participant_code=participant_code,
                                page_index=page_index,
                                app_name=app_name,
                                player_pk=p['id'],
                                subsession_pk=p['subsession__id'],
                                session_pk=session.pk,
                                url=url))

        ParticipantToPlayerLookup.objects.bulk_create(
            participant_to_player_lookups)
        session.participant_set.update(_max_page_index=page_index)

        with otree.db.idmap.use_cache():
            # possible optimization: check if
            # Subsession.creating_session == BaseSubsession.creating_session
            # if so, skip it.
            # but this will only help people who didn't override creating_session
            # in that case, the session usually creates quickly, anyway.
            for subsession in session.get_subsessions():
                subsession.before_session_starts()
                subsession.creating_session()
            otree.db.idmap.save_objects()

        # 2017-09-27: moving this inside the transaction
        session._set_admin_report_app_names()
        session.save()
        # we don't need to mark it ready=True here...because it's in a
        # transaction

    # this should happen after session.ready = True
    if room_name is not None:
        from otree.room import ROOM_DICT
        room = ROOM_DICT[room_name]
        room.set_session(session)

    return session
Exemplo n.º 4
0
def create_session(session_config_name, label='', num_participants=None,
                   special_category=None, _pre_create_id=None):

    # 2014-5-2: i could implement this by overriding the __init__ on the
    # Session model, but I don't really know how that works, and it seems to
    # be a bit discouraged: http://goo.gl/dEXZpv
    # 2014-9-22: preassign to groups for demo mode.

    try:
        session_config = get_session_configs_dict()[session_config_name]
    except KeyError:
        msg = 'Session type "{}" not found in settings.py'
        raise ValueError(msg.format(session_config_name))
    session = Session.objects.create(
        config=session_config,
        label=label,
        special_category=special_category,
        _pre_create_id=_pre_create_id,)

    def bulk_create(model, descriptions):
        model.objects.bulk_create([
            model(session=session, **description)
            for description in descriptions])
        return model.objects.filter(session=session).order_by('pk')

    if num_participants is None:
        c_special_catdemo = constants_internal.session_special_category_demo
        c_special_catbots = constants_internal.session_special_category_bots
        if special_category == c_special_catdemo:
            num_participants = session_config['num_demo_participants']
        elif special_category == c_special_catbots:
            num_participants = session_config['num_bots']

    # check that it divides evenly
    session_lcm = get_lcm(session_config)
    if num_participants % session_lcm:
        msg = (
            'Session Config {}: Number of participants ({}) does not divide '
            'evenly into group size ({})')
        raise ValueError(
            msg.format(session_config['name'], num_participants, session_lcm))

    start_order = list(range(num_participants))
    if session_config.get('random_start_order'):
        random.shuffle(start_order)

    participants = bulk_create(
        Participant,
        [{'id_in_session': i + 1, 'start_order': j}
         for i, j in enumerate(start_order)])

    for participant in participants:
        ParticipantLockModel(participant_code=participant.code).save()

    for app_name in session_config['app_sequence']:

        models_module = get_models_module(app_name)
        app_constants = get_app_constants(app_name)

        round_numbers = list(range(1, app_constants.num_rounds + 1))

        subs = bulk_create(
            models_module.Subsession,
            [{'round_number': round_number} for round_number in round_numbers])

        # Create players
        models_module.Player.objects.bulk_create([
            models_module.Player(
                session=session,
                subsession=subsession,
                round_number=round_number,
                participant=participant)
            for round_number, subsession in zip(round_numbers, subs)
            for participant in participants])

    session._create_groups_and_initialize()
    session.build_participant_to_player_lookups()
    session.ready = True
    session.save()

    return session
Exemplo n.º 5
0
def create_session(
        session_config_name, label='', num_participants=None,
        _pre_create_id=None,
        room_name=None, for_mturk=False, use_cli_bots=False,
        is_demo=False, force_browser_bots=False,
        honor_browser_bots_config=False, bot_case_number=None,
        edited_session_config_fields=None):

    session = None
    use_browser_bots = False
    participants = []
    edited_session_config_fields = edited_session_config_fields or {}

    with transaction.atomic():
        # 2014-5-2: i could implement this by overriding the __init__ on the
        # Session model, but I don't really know how that works, and it seems
        # to be a bit discouraged: http://goo.gl/dEXZpv
        # 2014-9-22: preassign to groups for demo mode.

        otree.db.idmap.activate_cache()

        try:
            session_config = SESSION_CONFIGS_DICT[session_config_name]
        except KeyError:
            msg = 'Session config "{}" not found in settings.SESSION_CONFIGS.'
            raise KeyError(msg.format(session_config_name)) from None
        else:
            # seems i need to copy and convert back to a session config
            # otherwise .copy() converts it to a simple dict
            session_config.update(edited_session_config_fields)
            session_config = SessionConfig(session_config.copy())
            # check validity and converts serialized decimal & currency values
            # back to their original data type (because they were serialized
            # when passed through channels
            session_config.clean()

        if force_browser_bots:
            use_browser_bots = True
        elif (session_config.get('use_browser_bots') and
              honor_browser_bots_config):
            use_browser_bots = True
        else:
            use_browser_bots = False
        if use_browser_bots and bot_case_number is None:
            # choose one randomly
            num_bot_cases = session_config.get_num_bot_cases()
            # choose bot case number randomly...maybe reconsider this?
            # we can only run one.
            bot_case_number = random.choice(range(num_bot_cases))

        session = Session.objects.create(
            config=session_config,
            label=label,
            _pre_create_id=_pre_create_id,
            use_browser_bots=use_browser_bots,
            is_demo=is_demo,
            _bot_case_number=bot_case_number)

        def bulk_create(model, descriptions):
            model.objects.bulk_create([
                model(session=session, **description)
                for description in descriptions])
            return model.objects.filter(session=session).order_by('pk')

        # check that it divides evenly
        session_lcm = session_config.get_lcm()
        if num_participants % session_lcm:
            msg = (
                'Session Config {}: Number of participants ({}) does not '
                'divide evenly into group size ({})'
            ).format(session_config['name'], num_participants, session_lcm)
            raise ValueError(msg)

        if for_mturk:
            session.mturk_num_participants = (
                    num_participants /
                    settings.MTURK_NUM_PARTICIPANTS_MULTIPLE)

        start_order = list(range(num_participants))
        if session_config.get('random_start_order'):
            random.shuffle(start_order)

        participants = bulk_create(
            Participant,
            [{
                'id_in_session': id_in_session,
                'start_order': j,
                # check if id_in_session is in the bots ID list
                '_is_bot': use_cli_bots or use_browser_bots,
             }
             for id_in_session, j in enumerate(start_order, start=1)])

        ParticipantLockModel.objects.bulk_create([
            ParticipantLockModel(participant_code=participant.code)
            for participant in participants])

        for app_name in session_config['app_sequence']:

            models_module = get_models_module(app_name)
            app_constants = get_app_constants(app_name)

            round_numbers = list(range(1, app_constants.num_rounds + 1))

            subs = bulk_create(
                models_module.Subsession,
                [{'round_number': round_number}
                 for round_number in round_numbers])

            # Create players
            models_module.Player.objects.bulk_create([
                models_module.Player(
                    session=session,
                    subsession=subsession,
                    round_number=round_number,
                    participant=participant)
                for round_number, subsession in zip(round_numbers, subs)
                for participant in participants])

        session._create_groups_and_initialize()

        session.build_participant_to_player_lookups()
        # automatically save all objects since the cache was activated:
        # Player, Group, Subsession, Participant, Session
        otree.db.idmap.save_objects()
        otree.db.idmap.deactivate_cache()

    if use_browser_bots:
        # what about clear_browser_bots? if session is created through
        # UI, when do we run that? it should be run when the session
        # is deleted
        try:
            for participant in participants:
                otree.bots.browser.initialize_bot(
                    participant.code)
        except:
            session.delete()
            raise

    session.ready = True
    session.save()

    # this should happen after session.ready = True
    if room_name is not None:
        from otree.room import ROOM_DICT
        room = ROOM_DICT[room_name]
        room.session = session

    return session