The Experiment Class
Experiments are designed in Dallinger by creating a custom subclass of the base Experiment class. The code for the Experiment class is in experiments.py. Unlike the other classes, each experiment involves only a single Experiment object and it is not stored as an entry in a corresponding table, rather each Experiment is a set of instructions that tell the server what to do with the database when the server receives requests from outside.
- class dallinger.experiment.Experiment(session=None)[source]
Define the structure of an experiment.
- verbose
Boolean, determines whether the experiment logs output when running. Default is True.
- task
String, the name of the experiment. Default is “Experiment title”.
- session
session, the experiment’s connection to the database.
- experiment_routes
Flask Blueprint for experiment. Functions and methods on the class should be registered as Flask routes using the
experiment_route()
decorator. Route functions can not be instance methods and should either be plain functions or classmethods. You can also register route functions at the module level using the standard route decorator on this Blueprint.
- recruiter
Reference to a Recruiter, the Dallinger class that recruits participants.
- initial_recruitment_size
int, the number of participants requested when the experiment first starts. Default is 1.
- known_classes
dictionary, the classes Dallinger can make in response to front-end requests. Experiments can add new classes to this dictionary.
- participant_constructor
Constructor for Participant objects. Callable returning an instance of
Participant
or a sub-class. Used bycreate_participant()
.
Sequence of dashboard route/function names that should be excluded from rendering as tabs in the dashboard view.
- channel
Optional Redis channel to subscribe to on launch. Note that if you set the channel, you will probably also want to override the
send()
method, since this is where messages from Redis will be consumed. Setting a value here will also result in the experiment being subscribed to thedallinger_control
channel for messages related to socket/subscription updates. This is also the defaultchannel_name
for messages sent using thepublish_to_subscribers()
method.
- public_properties
dictionary, the properties of this experiment that are exposed to the public over an AJAX call
- add_node_to_network(node, network)[source]
Add a node to a network.
This passes node to
add_node()
.
- assignment_abandoned(participant)[source]
What to do if a participant abandons the hit.
This runs when a notification from AWS is received indicating that participant has run out of time. Calls
fail_participant()
.
- assignment_reassigned(participant)[source]
What to do if the assignment assigned to a participant is reassigned to another participant while the first participant is still working.
This runs when a participant is created with the same assignment_id as another participant if the earlier participant still has the status “working”. Calls
fail_participant()
.
- assignment_returned(participant)[source]
What to do if a participant returns the hit.
This runs when a notification from AWS is received indicating that participant has returned the experiment assignment. Calls
fail_participant()
.
- attention_check(participant)[source]
Check if participant performed adequately.
Return a boolean value indicating whether the participant’s data is acceptable. This is mean to check the participant’s data to determine that they paid attention. This check will run once the participant completes the experiment. By default performs no checks and returns True. See also
data_check()
.
- attention_check_failed(participant)[source]
What to do if a participant fails the attention check.
Runs when participant has failed the
attention_check()
. By default callsfail_participant()
.
- bonus(participant)[source]
The bonus to be awarded to the given participant.
Return the value of the bonus to be paid to participant. By default returns 0.
- bonus_reason()[source]
The reason offered to the participant for giving the bonus.
Return a string that will be included in an email sent to the participant receiving a bonus. By default it is “Thank you for participating! Here is your bonus.”
- calculate_qualifications(participant)[source]
All the qualifications we want to assign to a worker.
This default implementation produces qualifications compatible with Dallinger’s standard recruiters, and the MTurkRecruiter in particular.
Workers will always be assigned one qualification specific to the experiment run. If a “group_name” config value is set, this will be parsed for additional qualifications to grant.
Return type is a list of dictionaries with “name”, “description”, and optionally “score” (an integer), or an empty list.
- collect(app_id, exp_config=None, bot=False, **kwargs)[source]
Collect data for the provided experiment id.
The
app_id
parameter must be a valid UUID. If an existing data file is found for the UUID it will be returned, otherwise - if the UUID is not already registered - the experiment will be run and data collected.See
run()
method for other parameters.
- create_participant(worker_id, hit_id, assignment_id, mode, recruiter_name=None, fingerprint_hash=None, entry_information=None)[source]
Creates and returns a new participant object. Uses
participant_constructor
as the constructor.- Parameters:
worker_id (str) – the recruiter Worker Id
hit_id (str) – the recruiter HIT Id
assignment_id (str) – the recruiter Assignment Id
mode (str) – the application mode
recruiter_name (str) – the recruiter name
fingerprint_hash (str) – the user’s fingerprint
entry_information – a JSON serializable data structure containing additional participant entry information
- Returns:
A
Participant
instance
- dashboard_database_actions()[source]
Returns a sequence of custom actions for the database dashboard. Each action must have a
title
and aname
corresponding to a method on the experiment class.The named methods should take a single
data
argument which will be a list of dicts representing the datatables rendering of a Dallinger model object. The named methods should return adict
containing a"message"
which will be displayed in the dashboard.Returns a single action referencing the
dashboard_fail()
method by default.
- dashboard_fail(data)[source]
Marks matching non-failed items as failed. Items are looked up by
id
andobject_type
(e.g."Participant"
).- Parameters:
data – A list of dicts representing model items to be marked as failed. Each must have an
id
and anobject_type
- Returns:
Returns a
dict
with a"message"
string indicating how many items were successfully marked as failed.
- data_check(participant)[source]
Check that the data are acceptable.
Return a boolean value indicating whether the participant’s data is acceptable. This is meant to check for missing or invalid data. This check will be run once the participant completes the experiment. By default performs no checks and returns True. See also,
attention_check()
.
- data_check_failed(participant)[source]
What to do if a participant fails the data check.
Runs when participant has failed
data_check()
. By default callsfail_participant()
.
- events_for_replay(session=None, target=None)[source]
Returns an ordered list of “events” for replaying. Experiments may override this method to provide custom replay logic. The “events” returned by this method will be passed to
replay_event()
. The default implementation simply returns allInfo
objects in the order they were created.
- classmethod extra_parameters()[source]
Override this classmethod to register new config variables. It is called during config load. See Extra Configuration for an example.
- exit_info_for(participant)[source]
An experiment can return a dictionary of infomation that will be shown to the participant at the very last point in their lifecycle, if the HIT is not submitted to an external recruitment service for submission.
For complete control over the exit page, a customized version of the
exit_recruiter.html
template can be included in the experient directory, and this will override the default provided by Dallinger.- Parameters:
participant – the
Participant
instance for which to calculate an exit value- Returns:
dict
which may be rendered to the worker as an HTML table when they submit their assigment.
- get_network_for_participant(participant)[source]
Find a network for a participant.
If no networks are available, None will be returned. By default participants can participate only once in each network and participants first complete networks with role=”practice” before doing all other networks in a random order.
- is_complete()[source]
Method for custom determination of experiment completion. Experiments should override this to provide custom experiment completion logic. Returns None to use the experiment server default logic, otherwise should return True or False.
- is_overrecruited(waiting_count)[source]
Returns True if the number of people waiting is in excess of the total number expected, indicating that this and subsequent users should skip the experiment. A quorum value of 0 means we don’t limit recruitment, and always return False.
- load_participant(assignment_id)[source]
Returns a participant object looked up by assignment_id.
Intended to allow a user to resume a session in a running experiment.
- Parameters:
assignment_id (str) – the recruiter Assignment Id
- Returns:
A
Participant
instance orNone
if there is not a single matching participant.
- classmethod make_uuid(app_id=None)[source]
Generates a new UUID. This is a class method and can be called as Experiment.make_uuid(). Takes an optional app_id which is converted to a string and, if it is a valid UUID, returned.
- normalize_entry_information(entry_information)[source]
Accepts a dictionary with information about a recruited user. Returns a dictionary containing data the needed to create or load a Dallinger Participant. The returned data should include valid
assignment_id
,worker_id
, andhit_id
values. It may also include anentry_information
key which should contain a transformedentry_information
dict which will be stored for newly created participants.By default, the extraction of these values is delegated to the recruiter’s normalize_entry_information method.
Returning a dictionary without valid
hit_id
,assignment_id
, orworker_id
will generally result in an exception.
- on_launch()[source]
This function is called upon experiment launch. Unlike the background tasks, this function is blocking: recruitment won’t start until the function has returned.
- participant_task_completed(participant)[source]
Called when an experiment task is first finished, and prior to recruiter submission, data and attendance checks.
Assigns the qualifications to the Participant, via their recruiter. These will include one Qualification for the experiment ID, and others for the configured group_name, if it’s been set.
Overrecruited participants don’t receive qualifications, since they haven’t actually completed the experiment. This allows them to remain eligible for future runs.
- Parameters:
participant – the
Participant
instance
- publish_to_subscribers(data, channel_name=None)[source]
Publish data to the given channel_name. Data will be sent to all channel subscribers, potentially including the experiment instance itself. If no
channel_name
is specified, then theExperiment
channel
value will be used (and the data will automatically be consumed bysend()
). Thedata
must be a string, it typically contains JSON.- Parameters:
data (str) – the message data to be send
channel_name (str) – the name of the channel to publish the data to
- receive_message(message, channel_name=None, participant=None, node=None, receive_time=None)[source]
Stub implementation of a websocket message processor. Messages are are queued to be processed asynchronously by
send()
and the worker runs this method to process those messages. Sub-classes that wish to handle incoming messages asynchronously should override this method. Generally this method should always be overridden whenever theExperiment
channel
attribute is set.message
is a string, e.g. containing JSON formatted data.Control messages about channel subscription and websocket connect/disconnect events are sent over the
"dallinger_control"
channel.This method is called synchronously when no participant or node id can be determined from the message.
- Parameters:
message (str) – a websocket message
channel_name (str) – The name of the channel the message was received on.
participant (
Participant
instance) – the experiment participant object responsible for the messagenode (
Node
instance) – the experiment node the message corresponds toreceive_time (datetime.datetime) – The time the message was received by the experiment
- recruit()[source]
Recruit participants to the experiment as needed.
This method runs whenever a participant successfully completes the experiment (participants who fail to finish successfully are automatically replaced). By default it recruits 1 participant at a time until all networks are full.
- replay_event(event)[source]
Stub method to replay an event returned by
events_for_replay()
. Experiments must override this method to provide replay support.
- replay_start()[source]
Stub method for starting an experiment replay. Experiments must override this method to provide replay support.
- replay_finish()[source]
Stub method for ending an experiment replay. Experiments must override this method to provide replay support.
- run(exp_config=None, app_id=None, bot=False, **kwargs)[source]
Deploy and run an experiment.
The exp_config object is either a dictionary or a
localconfig.LocalConfig
object with parameters specific to the experiment run grouped by section.
- save(*objects)[source]
Add all the objects to the session and commit them.
This only needs to be done for networks and participants.
- send(raw_message)[source]
Async implementation of websocket message processing. Attempts to extract a participant id or node id from the message, and send the message to be processed asynchronously by
receive_message()
If it fails to find a participant or node id in the message, then the message is processed synchronously usingreceive_message()
.raw_message
is a string that includes a channel name prefix, for example a JSON message for ashopping
channel might look like:'shopping:{"type":"buy","color":"blue","quantity":"2"}'
Control messages about channel subscription and websocket connect/disconnect events use the
dallinger_control
channel name.Experiments can override this method if they want to process all messages synchronously in a single application instance by default. For example if an experiment retains non-persisted state in an attribute of the experiment class that it uses for message responses then it’s best to override this method instead of
receive_message()
, and explicitly hand off state synchronization and other database writes to async worker events.- Parameters:
raw_message (str) – a formatted message string
'$channel_name:$data'
- submission_successful(participant)[source]
Run when a participant’s experiment submission passes data and attendence checks.
- Parameters:
participant – the
Participant
instance
- transformation_get_request(node, transformations)[source]
Run when a request to get transformations is complete.
- transformation_post_request(node, transformation)[source]
Run when a request to transform an info is complete.
- dallinger.experiment.experiment_route(rule, **kwargs)[source]
Creates a decorator to register experiment functions or classmethods as routes on the
Experiment.experiment_routes
blueprint. Accepts all standard flaskroute
arguments. The registration is deferred until experiment server setup to allow routes to be overridden.- Returns:
A decorator to register methods from a class as experiment routes.